Rust’s macros are strong and, unlike the string substitution macros of THE C language, now define current event handling instead.

The definition of a macro

Before refactoring the event-handling code, walk through the syntax defined by Rust macros.

The simplest macro definition

Rust’s macros use macro_rules! To declare rules

macro_rules! ten {
    () => { 10 };
}
fn main() {
    let x = 2* ten! (a);assert_eq!(20, x); // ten! [] or ten! {}
}
Copy the code

This is the simplest macro that executes from the left side of the bracket matching rule, from the right side, and returns a number directly. It’s easy to use, macros, you can use curly braces, curly braces, curly braces.

Match the token trees

Macros can match token trees as well as a FN keyword

macro_rules! foo {
    (fn) => {1}; }fn main() {
    letx = foo! (fn);
    assert_eq!(1, x);
}
Copy the code
Pass parameters to macros

The code above is 2 times the number 10 from executing the macro. Now let’s look at passing the expression to the macro

macro_rules! ten_times {
    ($e: expr) => { 10 * $e };
}
fn main() {
    letx = ten_times! (2);
    assert_eq!(20, x);
}
Copy the code

$e = expr; $e = expr; $e = expr; $e = expr

-Dan: An item or an expression wrapped in braces. -Dan: STMT, statement, pat, pattern, ty, ident ident, identifier, path. Paths like foo::bar are meta: types, such as #[… The #! […]. Inside things TT: a token tree

Try anything. Just take Pat

macro_rules! test {
    ( $e: expr, $pattern: pat ) => {
        match $e {
            $pattern => {
                true}, _ = >false}}}fn main() {
    let a = Some(true);
    letx = test! (a,Some(true));
    println!("{}", x);
}
Copy the code
repeat

This is an example from the macro section of Rust Book, where * means to reuse the contents of the $() package to process incoming values. In this case, multiple numbers can be processed

macro_rules! vec {
    ( $( $x:expr ),* ) => {
        {
            let mut temp_vec = Vec::new(); $( temp_vec.push($x); ) * temp_vec } }; }fn main() {
    let v = vec![1.2.3];
}
Copy the code

Use macros to unify event handling

Now that you have a general understanding of the syntax of Rust macros, let’s use macros to handle event handling. Before we apply macros, let’s think about one thing, usually when we write a function, it depends on what the function does, what the function needs to be signed. The most interesting thing about macros is that with enough imagination, you can make up your own way of using them. Let’s name this macro rule events_macro

events_macro! {
    keyboard: {
        key_escape: Escape,
        key_up: Up,
        key_down: Down
    },
    else: { quit: Quit { .. }}}Copy the code

We’re going to use the SDL event type in the macro rules, the keyboard keys and things like that, so we’re going to use the Ident, and we’re going to use the macro repetition mechanism, so we’re going to handle all the events the same way, except for the keyboard event, and then we’re going to handle the exit event, and we’re going to pass in a PAT

macro_rules! events_macro {
    ( keyboard: { $( $k_alias:ident : $k_sdl:ident ), * },
      else: { $( $e_alias:ident : $e_sdl:pat ), * }) => {
        use sdl2::EventPump;

        pub struct ImmediateEvents{$(pub $k_alias: Option<bool* $(>),pub $e_alias: bool ),*
        }

        impl ImmediateEvents {
            fn new() - >Self {
                Self {
                    $( $k_alias: None, )*
                    $( $e_alias: false,)*}}}pub struct Events {
            pump: EventPump,
            pub now: ImmediateEvents,
            $( pub $k_alias: bool) *}impl Events {
            pub fn new(pump: EventPump) -> Self {
                Self {
                    pump,
                    now: ImmediateEvents::new(),
                    $( $k_alias: false) *}}pub fn pump(&mut self) {
                self.now = ImmediateEvents::new();
                for event in self.pump.poll_iter() {
                    use sdl2::event::Event::*;
                    use sdl2::keyboard::Keycode::*;
                    match event {
                        $(KeyDown { keycode: Some($k_sdl), .. } = > {if !self.$k_alias {
                                self.now.$k_alias = Some(true);
                            }
                            self.$k_alias = true;
                        }), *
                        $(KeyUp { keycode: Some($k_sdl), .. } = > {self.now.$k_alias = Some(false);
                            self.$k_alias = false;
                        }), *
                        $($e_sdl => { self.now.$e_alias = true; }), * _ => {}}}}}}; }Copy the code

We use this macro in main.rs

#! [feature(uniform_paths)]

use sdl2::pixels::Color;

#[macro_use]
mod events;
events_macro! {
    keyboard: {
        key_escape: Escape,
        key_up: Up,
        key_down: Down
    },
    else: { quit: Quit { .. }}}fn main() {
    let sdl2_context = sdl2::init().unwrap();
    let video = sdl2_context.video().unwrap();
    let window = video
        .window("Arcade Shooter".800.600)
        .position_centered()
        .opengl()
        .build()
        .unwrap();
    let mut canvas = window.renderer().accelerated().build().unwrap();

    let mut event = Events::new(sdl2_context.event_pump().unwrap());
    canvas.set_draw_color(Color::RGB(0.0.0));
    canvas.clear();
    canvas.present();

    'running: loop {
        event.pump();
        if event.now.quit || event.now.key_escape == Some(true) {
            break 'running; }}}Copy the code

It is now extensible enough to define new keyboard events by simply changing the macro’s call-in.