Hi, I was writing a macro for instantiating a linked list where;
- Each list item is assigned a number
- Each list item is also passed the number of the final element in the first
The types for this linked list look like this;
trait Item<const END: usize> {}
struct ListItem<const NUM: usize, const END: usize, T: Item<END>>(T);
impl <const NUM: usize, const END: usize, T: Item<END>> Item<END> for ListItem<NUM, END, T> {}
struct EndItem<const END: usize>();
impl <const END: usize> Item<END> for EndItem<END> {}
The set of macros I have written for them look like this:
macro_rules! instantiate {
($a:expr, $b:expr) => {
(EndItem())
};
($a:expr, $($b:tt)*) => {
ListItem(instantiate!($($b)*))
}
}
macro_rules! make_type {
($num:expr) => {
EndItem::<$num>
};
(end $end:expr, $num:expr) => {
ListItem::<$num, $end, EndItem::<$end>>
};
(end $end:expr, $num:expr, $($c:tt)*) => {
ListItem::<$num, $end, make_type!(end $end, $($c)*)>
};
}
macro_rules! list {
(end $end:expr) => {
make_type!($end)()
};
(end $end:expr, $num:expr) => {
make_type!(end $end, $num)(instantiate!($num, $end))
};
(end $end:expr, $num:expr, $($c:tt)*) => {
make_type!(end $end, $num, $($c)*)(instantiate!($num, $($c)*, $end))
};
}
I have checked and this is working such that list!(end 4, 0, 1, 2, 3)
generates and instantiates a list of the correct type, but currently I'm having to put the value assigned to the final element first just so it's in a fixed place since after trying a few methods I couldn't seem to find a pattern where I can access the final expression passed into the macro.
I just wondered if it would be possible to write something like
($num:expr, $($c:tt)*; $end:expr) => {
make_type!(end $end, $num, $($c)*)(instantiate!($num, $($c)*, $end))
};
So that way the macro can be called more intuitively with the final item's value coming in the last place (I.E. list!(0, 1, 2, 3, 4)
rather than the current list!(end 4, 0, 1, 2, 3)
) but the macros is still able to pass the value to the preceding items.