DEV Community

toyster
toyster

Posted on

Macros

([ $( $elem:expr ),* ]) => // 0 or more [aa, bb, cc]
([ $( $elem:expr )* ]) => // 0 or more [aa bb cc]
([ $( $elem:expr ),+ ]) => // 1 or more [aa, bb, cc]
Enter fullscreen mode Exit fullscreen mode

outer bracket → pattern $ ( $elem:expr )*
expr → Expression
stmt → Statement
ty → type
tt → token tree
ident → identifier

JSON macro

This token tree pattern matches to first token tree, otherwise [10,20] is read as expression and looks for From[10,20] which is wrong
([ $( $elem:tt ),* ])

macro_rules! json {
  (null) => {Json::Null};
  ([ $( $elem:tt ),* ]) => {
      Json::Array(vec![ $( json!($elem) ),* ])
  };
// $value:expr, $value:tt (token tree works only)
  ({ $($key:tt : $value:expr),* }) => {
      {
          let mut fields = Box::new(HashMap::new());
          $( fields.insert($key.to_string(), json!($value)); )*
          Json::Object(fields)
      }
  };
  ($other:tt) => {
      Json::from($other)
  };
}
Enter fullscreen mode Exit fullscreen mode

For example,

59 |           Json::from($other)
   |           ^^^^^^^^^^ the trait `From<[{float}; 2]>` is not implemented for `Json`
...
74 |       let role = json!({
   |  ________________-
75 | |         "name": "movies",
76 | |         "actor": [10.0, 20.0]
77 | |     });
   | |______- in this macro invocationr
Enter fullscreen mode Exit fullscreen mode

This [10.0, 20.0] looks for From[{float}; 2 because it is trying to evaluate that expression. Instead use $value:tt instead. This converts to Json::Array(<[_]>::into_vec(box [Json::from(10.0), Json::from(20.0)])),This token tree pattern matches to first token tree, otherwise [10,20] is read as expression and looks for From[10,20] which is wrong ([ $( $elem:tt ),* ])

Internal rules pattern. This is extremely useful pattern

#[macro_export]
macro_rules! foo {
    (@as_expr $e:expr) => {$e};

    ($($tts:tt)*) => {
   foo!(@as_expr $($tts)*)
    };
}

/*
macro_rules! macro1 {
    () => { macro!(@macro2); } ;
    (@macro2) => { }
    }
}

*/

fn main() {
    foo!({
  println!("hello") ;
    });
}
Enter fullscreen mode Exit fullscreen mode

TT munchers

macro_rules! handle_operations {
    (up $($tt:tt)*) => {
        println!("up");
        handle_operations!($($tt)*);
    };
    (down $($tt:tt)*) => {
        println!("down");
        handle_operations!($($tt)*);
    };
    () => {};
}


fn main() {
    handle_operations!(up up down down);    
}
Enter fullscreen mode Exit fullscreen mode

Counting macro

    macro_rules! count {
        () => (0usize);
        ( $x:tt $($xs:tt)* ) => (1usize + count!($($xs)*));
    }
Enter fullscreen mode Exit fullscreen mode

Top comments (0)