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.