Как вложить макрос Rust, который оценивает список идентификаторов? - PullRequest
0 голосов
/ 23 марта 2020

Я использую макросы для настройки множества повторяющихся структур данных, функций, типов и т. Д. c ... для каждого из сигналов прерывания POSIX.

Я заметил, что копирую и вставляю свой список много сигналов, и я хотел, чтобы все было DRY, создав макрос, который расширился до списка сигналов.

Так что работает :

/* Empty trait used for typing addy::for<S: Signal>() */
trait Signal {}

/* Turns a list of identifiers into structs that 'implement' the Signal
 * trait so they can be used to type addy::for<S: Signal>()
*/
macro_rules! setup_signals {
    ($( $signal_name:ident),*) => {
        $(  
            struct $signal_name {}
            impl Signal for $signal_name {}
        )*
    };
}

/* The supported POSIX signals for addy */
setup_signals!(
    SIGABRT, SIGALRM,  SIGBUS,   SIGCHLD,
    SIGCONT, SIGFPE,   SIGHUP,   SIGILL,
    SIGINT,  SIGKILL,  SIGPIPE,  SIGPOLL,
    SIGPROF, SIGQUIT,  SIGSEGV,  SIGSTOP,
    SIGSYS,  SIGTERM,  SIGTRAP,  SIGTSTP,
    SIGTTIN, SIGTTOU,  SIGUSR1,  SIGUSR2,
    SIGURG,  SIGVTALRM, SIGXCPU, SIGXFSZ,
    SIGWINCH    
);

Однако, когда я пытаюсь создать макрос с этим списком идентификаторов, он терпит неудачу.

trait Signal {}
macro_rules! list_of_signals {
    () => {
        SIGABRT, SIGALRM,  SIGBUS,   SIGCHLD,
        SIGCONT, SIGFPE,   SIGHUP,   SIGILL,
        SIGINT,  SIGKILL,  SIGPIPE,  SIGPOLL,
        SIGPROF, SIGQUIT,  SIGSEGV,  SIGSTOP,
        SIGSYS,  SIGTERM,  SIGTRAP,  SIGTSTP,
        SIGTTIN, SIGTTOU,  SIGUSR1,  SIGUSR2,
        SIGURG,  SIGVTALRM, SIGXCPU, SIGXFSZ,
        SIGWINCH    
    };
}

macro_rules! setup_signals {
    ($( $signal_name:ty),*) => {
        $(  
            struct $signal_name {}
            impl Signal for $signal_name {}
        )*
    };
}

setup_signals!(
    list_of_signals!()
);

Это смущает меня, потому что я раньше использовал вложенные макросы.

macro_rules! GET_CURSOR_POSITION_SCAN_STR { () => { "\x1b[{d};{d}R" };}
/* ---///--- */
// Parse the result from the buffer: ESC [ rows ; cols R
let position = scan_fmt!(buffer, GET_CURSOR_POSITION_SCAN_STR!(), u16, u16)
                        .chain_err(|| "Failed to parse cursor position")?;

Я вижу, что одно отличие состоит в том, что в этом примере вложенный макрос расширяется до &str, а мой текущий вложенный макрос расширяется до списка идентификаторов.

Как я могу иметь list_of_signals!() развернуть аналогичным образом, чтобы я мог сохранить свой код DRY?

...