use quote::ToTokens;
use syn::{parse2, parse_str, DeriveInput, ItemImpl};
macro_rules! test_all {
(
$(
$test_name:ident: {
$($input:tt)*
} => {
$($output:tt)*
};
)*
) => {
$(
#[test]
fn $test_name() {
let input: DeriveInput = parse_str(stringify!($($input)*)).expect("failed to parse input as `DeriveInput`");
let expected_str = stringify!($($output)*);
let expected: ItemImpl = parse_str(expected_str).expect("failed to parse expected output as `ItemImpl`");
let output_tokens = crate::derive_parse_internal(input);
let output: ItemImpl = parse2(output_tokens.clone())
.unwrap_or_else(|err| panic!(
"failed to parse output as `ItemImpl`: {}\noutput_tokens = {:?}",
err,
output_tokens.to_string(),
));
if output != expected {
panic!(
"output != expected\noutput = {:?},\nexpected = {:?}",
output_tokens.to_string(),
expected.to_token_stream().to_string(),
)
}
}
)*
}
}
test_all! {
simple_input: {
struct Foo {
bar: Bar,
baz: Baz,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let bar: Bar = __parse_input.parse()?;
let baz: Baz = __parse_input.parse()?;
Ok(Foo {
bar,
baz,
})
}
}
};
generic_struct: {
struct Foo<B, Q: Quack>
where <B as Bar>::Qux: Quack,
{
bar: B,
baz: Baz,
quacker: Q,
}
} => {
impl<B: ::syn::parse::Parse, Q: Quack + ::syn::parse::Parse> ::syn::parse::Parse for Foo<B, Q>
where <B as Bar>::Qux: Quack,
{
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let bar: B = __parse_input.parse()?;
let baz: Baz = __parse_input.parse()?;
let quacker: Q = __parse_input.parse()?;
Ok(Foo {
bar,
baz,
quacker,
})
}
}
};
simple_attrs: {
struct Foo {
bar: Bar,
#[paren]
paren: syn::token::Paren,
#[inside(paren)]
baz: Baz,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let bar: Bar = __parse_input.parse()?;
let __paren_backing_token_stream;
let paren: syn::token::Paren =
::syn::parenthesized!(__paren_backing_token_stream in __parse_input);
let baz: Baz =
__paren_backing_token_stream.parse()?;
Ok(Foo {
bar,
paren,
baz,
})
}
}
};
nested_attrs: {
struct Foo {
bar: Bar,
#[bracket]
fst: syn::token::Bracket,
#[inside(fst)]
#[brace]
snd: syn::token::Brace,
#[inside(snd)]
baz: Baz,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let bar: Bar = __parse_input.parse()?;
let __fst_backing_token_stream;
let fst: syn::token::Bracket =
::syn::bracketed!(__fst_backing_token_stream in __parse_input);
let __snd_backing_token_stream;
let snd: syn::token::Brace =
::syn::braced!(__snd_backing_token_stream in __fst_backing_token_stream);
let baz: Baz = __snd_backing_token_stream.parse()?;
Ok(Foo {
bar,
fst,
snd,
baz,
})
}
}
};
struct_peek: {
struct Foo {
bar: Bar,
#[peek_with(|p| !p.is_empty())]
baz: Baz,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let bar: Bar = __parse_input.parse()?;
let baz: Baz = match (|p| !p.is_empty())(__parse_input) {
true => Some(__parse_input.parse()?),
false => None,
};
Ok(Foo {
bar,
baz,
})
}
}
};
parse_if_peek: {
struct Foo {
at_symbol: Option<Token![@]>,
#[parse_if(at_symbol.is_some())]
name: Ident,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let at_symbol: Option<Token![@]> = __parse_input.parse()?;
let name: Ident = match at_symbol.is_some() {
true => Some(__parse_input.parse()?),
false => None,
};
Ok(Foo {
at_symbol,
name,
})
}
}
};
simple_prefix: {
struct Field {
name: Ident,
#[prefix(Token![:])]
ty: Type,
}
} => {
impl ::syn::parse::Parse for Field {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let name: Ident = __parse_input.parse()?;
let _: Token![:] = __parse_input.parse()?;
let ty: Type = __parse_input.parse()?;
Ok(Field {
name,
ty,
})
}
}
};
simple_postfix: {
struct Field {
#[postfix(Token![:])]
name: Ident,
ty: Type,
}
} => {
impl ::syn::parse::Parse for Field {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let name: Ident = __parse_input.parse()?;
let _: Token![:] = __parse_input.parse()?;
let ty: Type = __parse_input.parse()?;
Ok(Field {
name,
ty,
})
}
}
};
prefix_as_parse_if: {
struct Field {
name: Ident,
#[prefix(Token![:])]
ty: Type,
#[prefix(Option<Token![=]> as eq_token)]
#[parse_if(eq_token.is_some())]
value: Option<Expr>,
}
} => {
impl ::syn::parse::Parse for Field {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let name: Ident = __parse_input.parse()?;
let _: Token![:] = __parse_input.parse()?;
let ty: Type = __parse_input.parse()?;
let eq_token: Option<Token![=]> = __parse_input.parse()?;
let value: Option<Expr> = match eq_token.is_some() {
true => Some(__parse_input.parse()?),
false => None,
};
Ok(Field {
name,
ty,
value,
})
}
}
};
prefix_inside: {
struct Foo {
#[paren]
paren: token::Paren,
#[prefix(Token![=>] in paren)]
#[inside(paren)]
ident: Ident,
}
} => {
impl ::syn::parse::Parse for Foo {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let __paren_backing_token_stream;
let paren: token::Paren =
::syn::parenthesized!(__paren_backing_token_stream in __parse_input);
let _: Token![=>] = __paren_backing_token_stream.parse()?;
let ident: Ident = __paren_backing_token_stream.parse()?;
Ok(Foo {
paren,
ident,
})
}
}
};
basic_peeks: {
enum FnOrIdent {
#[peek(token::Fn, name = "function")]
Fn(token::Fn),
#[peek_with(|_| true, name = "identifier")]
Ident(Ident),
}
} => {
impl ::syn::parse::Parse for FnOrIdent {
fn parse (__parse_input: ::syn::parse::ParseStream) -> ::syn:: Result<Self> {
if __parse_input.peek(token::Fn) {
let _field_0: token::Fn = __parse_input.parse()?;
return Ok(Self::Fn(_field_0,));
}
if (|_| true)(__parse_input) {
let _field_0: Ident = __parse_input.parse()?;
return Ok(Self::Ident(_field_0,));
}
Err (__parse_input.error("expected either function or identifier"))
}
}
};
calls: {
struct Calls {
#[call(Attribute::parse_outer)]
attrs: Vec<Attribute>,
#[call(|_| Ok(3))]
x: u32,
#[call(|_| Ok(x + 1))]
y: u32,
}
} => {
impl ::syn::parse::Parse for Calls {
fn parse(__parse_input: ::syn::parse::ParseStream) -> ::syn::Result<Self> {
let attrs: Vec<Attribute> = {
let result: ::syn::Result<_> = (Attribute::parse_outer)(&__parse_input);
result?
};
let x: u32 = {
let result: ::syn::Result<_> = (|_| Ok(3))(&__parse_input);
result?
};
let y: u32 = {
let result: ::syn::Result<_> = (|_| Ok(x + 1))(&__parse_input);
result?
};
Ok(Calls { attrs, x, y, })
}
}
};
}