-
-
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)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// 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