macro_rules! parse_split_generics_and_where {
(
$(:: $(@$leading:tt@)? )? $first:ident $(:: $trailing:ident)* ! $prefix:tt
($($generics:tt)*)
) => { ... };
}
Available on crate feature
generics_parsing
only.Expand description
For parsing item definitions, transforming generics to a form easily parsable by a callback macro.
Examples
Basic
Basic example of using this macro, and what it passes to a callback macro.
For a more realistic example you can look at the one below
use core_extensions::parse_split_generics_and_where;
{
assert_eq!(hello(), "world")
}
// `parse_split_generics_and_where` calls `crate::foo` here
parse_split_generics_and_where! {
foo!{
// The first tokens passed to the `crate::foo` macro
hello "world" foo bar
}
(
// The parsed tokens
<'a: 'b, 'b, T: 'a + Foo = Bar, const X: u32 = 10, U = Baz, V> (param: Type) -> u32
where
T: Bar
{ println }
)
}
#[macro_export]
macro_rules! foo {
(
$fn_name:ident $string:literal foo bar
// The generic paremeters in the order they came in
// Bounds always have a trailing `+``
(
('a:('b +))
('b:())
(type T:('a + Foo +) = $def_t:ty,)
(const X: $ty_x:ty = $def_x:expr,)
(type U:() = $def_u:ty,)
(type V:(),)
)
// The generic parameters are classified by kind
// Bounds always have a trailing `+``
// Generic parameters always have a trailing `,`
(
('a:('b +), 'b:(),) // lifetimes
(T:('a + Foo +) = $defb_t:ty, U:() = $defb_u:ty, V:(),) // types
(X: $tyb_x:ty = $defb_x:expr,) // constants
)
// before the where clause
((param: Type) -> u32 )
// inside the where clause
(T: Bar,)
// after the where clause
( { println } )
) => {
fn $fn_name() -> &'static str {
$string
}
};
($($tt:tt)*) => { compile_error!{ stringify!($($tt)*) } }
}
Derive macro
This demonstrates how you can implement a derive through a macro_rules!
macro.
use core_extensions::parse_split_generics_and_where;
fn main() {
assert_eq!(Foo{bar: "hi", baz: vec![0]}.add_up(), 2);
assert_eq!(Foo{bar: "hello", baz: vec![0]}.add_up(), 5);
assert_eq!(Foo{bar: "hello", baz: vec![3]}.add_up(), 8);
assert_eq!(Foo{bar: "hello", baz: vec![3, 5]}.add_up(), 13);
}
crate::derives!{
#[derive(crate::derive_AddUp)]
struct Foo<T> {
bar: &'static str,
baz: T,
}
}
pub trait AddUp {
fn add_up(&self) -> u128;
}
impl AddUp for u8 {
fn add_up(&self) -> u128 {
*self as u128
}
}
impl AddUp for &str {
fn add_up(&self) -> u128 {
self.len() as u128
}
}
impl<T: AddUp> AddUp for &[T] {
fn add_up(&self) -> u128 {
self.iter().map(AddUp::add_up).sum()
}
}
impl<T: AddUp> AddUp for Vec<T> {
fn add_up(&self) -> u128 {
self.iter().map(AddUp::add_up).sum()
}
}
#[macro_export]
macro_rules! derives {
(#[derive $derives:tt] $($type:tt)*) => {
$($type)*
$crate::derives!{@inner $derives {$($type)*} }
};
(@inner ($($derive:path),*) $type:tt ) => {
$( $derive! $type )*
}
}
#[macro_export]
macro_rules! derive_AddUp {
(
$(#[$attr:meta])*
$vis:vis
struct $name:ident $($generics:tt)*
) => {
parse_split_generics_and_where!{
$crate::__priv_derive_AddUp! {
$name,
}
($($generics)*)
}
}
}
#[doc(hidden)]
#[macro_export]
macro_rules! __priv_derive_AddUp{
(
$name:ident,
(
$( ($lt:lifetime :( $($lt_bounds:tt)* )) )*
$((
$( type $typ:ident :($($ty_bound:tt)*) $(= $ty_default:ty )? , )?
$( const $const:ident :($($const_bound:tt)*) $(= $const_default:expr )? , )?
))*
)
$generic_in_order:tt
$__between_generics_and_where:tt
( $($where_preds:tt)* )
({
$(
$(#[$fattr:meta])* $fvis:vis $fname:ident : $fty:ty
),* $(,)?
})
) => {
impl<
$($lt: $($lt_bounds)* ,)*
$(
$($typ: $($ty_bound)* $crate::AddUp + )?
$(const $const: $($const_bound)* )?,
)*
> $name<$($lt,)* $($($typ)? $($const)? ,)*>
where
$($where_preds)*
{
fn add_up(&self) -> u128 {
0
$( + self.$fname.add_up() )*
}
}
};
}