Skip to content

Instantly share code, notes, and snippets.

@durka
Forked from anonymous/playground.rs
Last active October 19, 2020 23:15
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save durka/9fc479de2555225a787f to your computer and use it in GitHub Desktop.
Save durka/9fc479de2555225a787f to your computer and use it in GitHub Desktop.
Rust macro that splits a list of expressions in half (at compile time)
/// strategy:
/// - first copy the list of exprs -- the copy will just be used as a counter
/// - then, starting with all the exprs in a "left" list and an empty "right" list:
/// - move one expr at a time from "left" to "right", and decrement the counter _twice_
/// - when the counter is zero, the halving is complete
/// - if there were an odd number of exprs, a compile error tells you about it
/// the macro is in continuation passing style, so you pass in a macro invocation and it will be called
/// twice, first with the "left" and then with the "right" (enclosed in square brackets) inserted as the last argument
macro_rules! halve {
// internal rules
// these rules split the exprs into "left" and "right"
// - finished: hand off to the continuation macro
(@split [$mac:ident!($($arg:expr),*)] $left:tt $right:tt [])
=> { ($mac!($($arg,)* $right), $mac!($($arg,)* $left)) };
// - counter = 1 (meaning there were an odd number of exprs to start!)
(@split $mac:tt [$head:expr, $($tail:expr),+] [$($right:expr),*] [$a:expr])
=> {{ let error: () = "odd number of expressions passed to halve!"; }};
// - counter = 2
(@split $mac:tt [$head:expr, $($tail:expr),+] [$($right:expr),*] [$a:expr, $b:expr])
=> { halve!(@split $mac [$($tail),+] [$($right,)* $head] []) };
// - counter > 2
(@split $mac:tt [$head:expr, $($tail:expr),+] [$($right:expr),*] [$a:expr, $b:expr, $($more:expr),+])
=> { halve!(@split $mac [$($tail),+] [$($right,)* $head] [$($more),+]) };
// external entry point rule
($mac:ident!($($arg:expr),*): $($x:expr),*)
=> { halve!(@split [$mac!($($arg),*)] [$($x),*] [] [$($x),*]) }
// ^ continuation ^ left ^ right ^ counter
}
fn main() {
halve!(println!("{:?}"): 1, 2, 3, 4, 5, 6);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment