pub use proc_macro::TokenStream;
pub use proc_macro2::TokenStream as TokenStream2;
pub use syn::{parse, parse_str, DeriveInput};
#[macro_export]
macro_rules! decl_derive {
([$derives:ident $($derive_t:tt)*] => $inner:path) => {
#[proc_macro_derive($derives $($derive_t)*)]
#[allow(non_snake_case)]
pub fn $derives(
i: $crate::macros::TokenStream
) -> $crate::macros::TokenStream
{
let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i)
.expect(concat!("Failed to parse input to `#[derive(",
stringify!($derives),
")]`"));
$inner($crate::Structure::new(&parsed)).into()
}
};
}
#[macro_export]
macro_rules! decl_attribute {
([$attribute:ident] => $inner:path) => {
#[proc_macro_attribute]
pub fn $attribute(
attr: $crate::macros::TokenStream,
i: $crate::macros::TokenStream,
) -> $crate::macros::TokenStream {
let parsed = $crate::macros::parse::<$crate::macros::DeriveInput>(i).expect(concat!(
"Failed to parse input to `#[",
stringify!($attribute),
"]`"
));
$inner(attr.into(), $crate::Structure::new(&parsed)).into()
}
};
}
#[macro_export]
macro_rules! test_derive {
($name:path { $($i:tt)* } expands to { $($o:tt)* }) => {
{
#[allow(dead_code)]
fn ensure_compiles() {
$($i)*
$($o)*
}
test_derive!($name { $($i)* } expands to { $($o)* } no_build);
}
};
($name:path { $($i:tt)* } expands to { $($o:tt)* } no_build) => {
{
let i = stringify!( $($i)* );
let parsed = $crate::macros::parse_str::<$crate::macros::DeriveInput>(i)
.expect(concat!("Failed to parse input to `#[derive(",
stringify!($name),
")]`"));
let res = $name($crate::Structure::new(&parsed));
let expected = stringify!( $($o)* )
.parse::<$crate::macros::TokenStream2>()
.expect("output should be a valid TokenStream");
let mut expected_toks = $crate::macros::TokenStream2::from(expected);
if res.to_string() != expected_toks.to_string() {
panic!("\
test_derive failed:
expected:
```
{}
```
got:
```
{}
```\n",
$crate::unpretty_print(&expected_toks),
$crate::unpretty_print(&res),
);
}
}
};
}
#[cfg(feature = "simple-derive")]
#[macro_export]
macro_rules! simple_derive {
(
$iname:ident impl $path:path { $($rest:tt)* }
) => {
simple_derive!(__I [$iname, $path] { $($rest)* } [] []);
};
(
__I $opt:tt {
filter($s:ident) {
$($body:tt)*
}
$($rest:tt)*
} [$($done:tt)*] [$($filter:tt)*]
) => {
simple_derive!(
__I $opt { $($rest)* } [$($done)*] [
$($filter)*
[
st_name = $s,
body = {
$($body)*
},
]
]
);
};
(
__I $opt:tt {
fn $fn_name:ident (&self as $s:ident $($params:tt)*) $(-> $t:ty)* {
$($body:tt)*
}
$($rest:tt)*
} [$($done:tt)*] [$($filter:tt)*]
) => {
simple_derive!(
__I $opt { $($rest)* } [
$($done)*
[
st_name = $s,
bind_style = Ref,
body = { $($body)* },
result = result,
expanded = {
fn $fn_name(&self $($params)*) $(-> $t)* {
match *self { #result }
}
},
]
] [$($filter)*]
);
};
(
__I $opt:tt {
fn $fn_name:ident (&mut self as $s:ident $($params:tt)*) $(-> $t:ty)* {
$($body:tt)*
}
$($rest:tt)*
} [$($done:tt)*] [$($filter:tt)*]
) => {
simple_derive!(
__I $opt { $($rest)* } [
$($done)*
[
st_name = $s,
bind_style = RefMut,
body = { $($body)* },
result = result,
expanded = {
fn $fn_name(&mut self $($params)*) $(-> $t)* {
match *self { #result }
}
},
]
] [$($filter)*]
);
};
(
__I $opt:tt {
fn $fn_name:ident (self as $s:ident $($params:tt)*) $(-> $t:ty)* {
$($body:tt)*
}
$($rest:tt)*
} [$($done:tt)*] [$($filter:tt)*]
) => {
simple_derive!(
__I $opt { $($rest)* } [
$($done)*
[
st_name = $s,
bind_style = Move,
body = { $($body)* },
result = result,
expanded = {
fn $fn_name(self $($params)*) $(-> $t)* {
match self { #result }
}
},
]
] [$($filter)*]
);
};
(
__I [$iname:ident, $path:path] {} [$(
[
st_name = $st_name:ident,
bind_style = $bind_style:ident,
body = $body:tt,
result = $result:ident,
expanded = { $($expanded:tt)* },
]
)*] [$(
[
st_name = $filter_st_name:ident,
body = $filter_body:tt,
]
)*]
) => {
fn $iname(mut st: $crate::Structure) -> $crate::macros::TokenStream2 {
let _ = &mut st;
$(
{
let $filter_st_name = &mut st;
$filter_body
}
)*
$(
let $result = {
let mut $st_name = st.clone();
$st_name.bind_with(|_| ::synstructure::BindStyle::$bind_style);
let $result = {
$body
};
quote!{ $($expanded)* }
};
)*
st.bound_impl(quote!($path), quote!{
$(#$result)*
})
}
}
}