Reputation: 6516
My goal is to write a macro expand!
such that:
struct A;
struct B;
struct Mut<T>;
expand!() => ()
expand!(A) => (A,)
expand!(mut A) => (Mut<A>,)
expand!(A, mut B) => (A, Mut<B>,)
// etc
[Edit] added trailing comma for consistent tuple syntax.
I wrote this macro so far:
macro_rules! to_type {
( $ty:ty ) => { $ty };
( mut $ty:ty ) => { Mut<$ty> };
}
macro_rules! expand {
( $( $(mut)? $ty:ty ),* ) => {
(
$( to_type!($ty) ),*
,)
};
}
What I'm struggling with, is capturing the mut
token. How can I assign it to a variable and reuse it in the macro body? Is it possible to work on more than 1 token at a time?
Upvotes: 2
Views: 1194
Reputation: 36071
Something like this?
macro_rules! expand {
(@phase2($($ty_final:ty),*),) => {
($($ty_final,)*)
};
(@phase2($($ty_final:ty),*), mut $ty:ty, $($rest:tt)*) => {
expand!(@phase2($($ty_final,)* Mut::<$ty>), $($rest)*)
};
(@phase2($($ty_final:ty),*), $ty:ty, $($rest:tt)*) => {
expand!(@phase2($($ty_final,)* $ty), $($rest)*)
};
($($t:tt)*) => {
expand!(@phase2(), $($t)*)
};
}
struct A;
struct B;
struct Mut<T>(std::marker::PhantomData<T>);
fn main() {
#[allow(unused_parens)]
let _: expand!() = ();
#[allow(unused_parens)]
let _: expand!(A,) = (A,);
#[allow(unused_parens)]
let _: expand!(mut B,) = (Mut::<B>(Default::default()),);
#[allow(unused_parens)]
let _: expand!(A, mut B,) = (A, Mut::<B>(Default::default()));
}
Upvotes: 2