#![deny(unsafe_code)] #![no_implicit_prelude] use ::quote::quote as q; mod test_util; use test_util::*; #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyUnit; #[test] fn parse_unit() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { () }).unwrap(), MyUnit); ::std::assert_eq!( parse(q! { (1) }).unwrap_err_string(), "unexpected token `1`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyUnnamedEmpty(); #[test] fn parse_unnamed_empty() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { () }).unwrap(), MyUnnamedEmpty()); ::std::assert_eq!( parse(q! { (1) }).unwrap_err_string(), "unexpected token `1`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent)] struct MyNewtype(::std::string::String); #[test] fn parse_newtype() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { "qwerty" }).unwrap(), MyNewtype("qwerty".into())); ::std::assert_eq!( parse(q! { 123 }).unwrap_err_string(), "expected string literal" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyUnnamed(i32, ::std::string::String); #[test] fn parse_unnamed() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { (123, "abc") }).unwrap(), MyUnnamed(123, "abc".into()) ); ::std::assert_eq!( parse(q! { (123) }).unwrap_err_string(), "missing required field 1" ); ::std::assert_eq!( parse(q! { (123, "abc", true) }).unwrap_err_string(), "unexpected token `true`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamedEmpty {} #[test] fn parse_named_empty() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { {} }).unwrap(), MyNamedEmpty {}); ::std::assert_eq!( parse(q! { {a = 123} }).unwrap_err_string(), "unknown field `a`" ); ::std::assert_eq!(parse_flag::().unwrap(), MyNamedEmpty {}); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamed { a: i32, b: ::std::string::String, } #[test] fn parse_named() { use ::std::prelude::v1::*; let parse = parse_meta::; let t = MyNamed { a: 123, b: "asdf".into(), }; ::std::assert_eq!(parse(q! { {a = 123, b = "asdf"} }).unwrap(), t); ::std::assert_eq!(parse(q! { {a(123), b = "asdf"} }).unwrap(), t); ::std::assert_eq!(parse(q! { {a = 123, b("asdf")} }).unwrap(), t); ::std::assert_eq!(parse(q! { {a(123), b("asdf")} }).unwrap(), t); ::std::assert_eq!( parse(q! { {} }).unwrap_err_string(), "missing required field `a`, missing required field `b`" ); ::std::assert_eq!( parse(q! { {b("asdf")} }).unwrap_err_string(), "missing required field `a`" ); ::std::assert_eq!( parse(q! { {a(123)} }).unwrap_err_string(), "missing required field `b`" ); ::std::assert_eq!( parse(q! { {a(123), b("asdf"), c(true)} }).unwrap_err_string(), "unknown field `c`" ); ::std::assert_eq!( parse(q! { {a(123), b("asdf"), a(456)} }).unwrap_err_string(), "duplicate attribute for `a`" ); ::std::assert_eq!( parse(q! { {a(123), b("asdf"), a(456), a("456") } }).unwrap_err_string(), "duplicate attribute for `a`, duplicate attribute for `a`, expected integer literal" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamedChild { c: i32, #[deluxe(flatten)] d: MyNamed, } #[test] fn parse_named_flat() { use ::std::prelude::v1::*; let parse = parse_meta::; let t = MyNamedChild { c: 900, d: MyNamed { a: 100, b: "qwerty".into(), }, }; ::std::assert_eq!(parse(q! { {a = 100, b = "qwerty", c = 900} }).unwrap(), t); ::std::assert_eq!( parse(q! { {} }).unwrap_err_string(), "missing required field `a`, missing required field `b`, missing required field `c`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamedChildPrefixed { c: i32, #[deluxe(flatten(prefix = d))] d: MyNamed, } #[test] fn parse_named_flat_prefixed() { use ::std::prelude::v1::*; let parse = parse_meta::; let t = MyNamedChildPrefixed { c: 900, d: MyNamed { a: 100, b: "qwerty".into(), }, }; ::std::assert_eq!( parse(q! { {d::a = 100, d::b = "qwerty", c = 900} }).unwrap(), t ); ::std::assert_eq!( parse(q! { {} }).unwrap_err_string(), "missing required field `d::a`, missing required field `d::b`, missing required field `c`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamedChildLongPrefixed { c: i32, #[deluxe(flatten(prefix = d::e))] d: MyNamed, #[deluxe(flatten(prefix = d::e2))] d2: MyNamed, } #[test] fn parse_named_flat_long_prefixed() { use ::std::prelude::v1::*; let parse = parse_meta::; let t = MyNamedChildLongPrefixed { c: 900, d: MyNamed { a: 100, b: "qwerty".into(), }, d2: MyNamed { a: 200, b: "uiop".into(), }, }; ::std::assert_eq!( parse( q! { {d::e::a = 100, d::e::b = "qwerty", d::e2::b = "uiop", d::e2::a = 200, c = 900} } ) .unwrap(), t ); ::std::assert_eq!( parse(q! { {} }).unwrap_err_string(), "missing required field `d::e::a`, missing required field `d::e::b`, \ missing required field `d::e2::a`, missing required field `d::e2::b`, \ missing required field `c`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyNamedComplex { idents: ::std::vec::Vec<::syn::Ident>, #[deluxe(skip)] skipped: bool, #[deluxe(append)] exprs: ::std::vec::Vec<::syn::Expr>, #[deluxe(rest)] rest: ::std::collections::HashMap<::syn::Path, ::syn::Expr>, } #[test] fn vec_field() { use ::std::prelude::v1::*; fn cs() -> ::proc_macro2::Span { ::proc_macro2::Span::call_site() } let parse = parse_meta::; ::std::assert_eq!( parse(q! { { } }).unwrap_err_string(), "missing required field `idents`" ); ::std::assert_eq!( parse(q! { { idents } }).unwrap_err_string(), "unexpected flag, expected `=` or parentheses" ); ::std::assert_eq!( parse(q! { { idents = [] } }).unwrap().idents, &[] as &[::syn::Ident] ); ::std::assert_eq!( parse(q! { { idents() } }).unwrap().idents, &[] as &[::syn::Ident] ); let hello_world = &[ ::syn::Ident::new("hello", cs()), ::syn::Ident::new("world", cs()), ]; ::std::assert_eq!( parse(q! { { idents = [hello, world] } }).unwrap().idents, hello_world, ); ::std::assert_eq!( parse(q! { { idents = [hello, world,] } }).unwrap().idents, hello_world, ); ::std::assert_eq!( parse(q! { { idents(hello, world) } }).unwrap().idents, hello_world, ); ::std::assert_eq!( parse(q! { { idents(hello, world,) } }).unwrap().idents, hello_world, ); ::std::assert_eq!( parse(q! { { idents = (hello, world) } }).unwrap_err_string(), "expected square brackets" ); ::std::assert_eq!( parse(q! { { idents = [hello world] } }).unwrap_err_string(), "expected `,`" ); ::std::assert_eq!( parse(q! { { idents = [hello, 123, world] } }).unwrap_err_string(), "expected ident" ); ::std::assert_eq!( parse(q! { { idents = [hello, 123, world, 456, moon] } }).unwrap_err_string(), "expected ident, expected ident" ); } #[test] fn skipped_field_rest() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert!(!parse(q! { { idents = [] } }).unwrap().skipped); ::std::assert_eq!( parse(q! { { idents = [], skipped = true } }).unwrap(), MyNamedComplex { idents: ::std::vec![], skipped: false, exprs: ::std::vec![], rest: [( ::syn::parse_quote! { skipped }, ::syn::parse_quote! { true }, )] .into_iter() .collect(), }, ); } impl MyNamedComplex { #[inline] fn exprs_str(&self) -> ::std::string::String { use ::quote::ToTokens; use ::std::prelude::v1::*; self.exprs .iter() .map(|e| ::std::format!("({})", e.to_token_stream())) .collect::>() .join(", ") } #[inline] fn rest_str(&self) -> ::std::string::String { use ::quote::ToTokens; use ::std::prelude::v1::*; let mut rest = self.rest.iter().collect::>(); rest.sort_by_key(|(k, _)| k.to_token_stream().to_string()); rest.into_iter() .map(|(k, v)| ::std::format!("({} => {})", k.to_token_stream(), v.to_token_stream())) .collect::>() .join(", ") } } #[test] fn struct_append() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { { idents = [] } }).unwrap().exprs, []); ::std::assert_eq!( parse(q! { { idents = [], exprs = {} } }) .unwrap() .exprs_str(), "({ })", ); ::std::assert_eq!( parse(q! { { idents = [], exprs = {}, exprs = 123 + 4 } }) .unwrap() .exprs_str(), "({ }), (123 + 4)", ); ::std::assert_eq!( parse(q! { { idents = [], exprs = ! } }).unwrap_err_string(), "unexpected end of input, expected expression" ); } #[test] fn struct_rest() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { { idents = [] } }).unwrap().exprs, []); ::std::assert_eq!( parse(q! { { idents = [], abcd = 123 + 4 } }) .unwrap() .rest_str(), "(abcd => 123 + 4)", ); ::std::assert_eq!( parse(q! { { idents = [], abcd = 123 + 4, hello::world = { "str" } } }) .unwrap() .rest_str(), r#"(abcd => 123 + 4), (hello :: world => { "str" })"#, ); ::std::assert_eq!( parse(q! { { idents = [], abcd = 123 + 4, hello::world = { "str" }, exprs = 126 - 5 } }) .unwrap() .rest_str(), r#"(abcd => 123 + 4), (hello :: world => { "str" })"#, ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyUnnamedRest(i32, #[deluxe(flatten)] ::std::vec::Vec); #[test] fn tuple_struct_rest() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { () }).unwrap_err_string(), "missing required field 0" ); ::std::assert_eq!(parse(q! { (1) }).unwrap(), MyUnnamedRest(1, Vec::new())); ::std::assert_eq!( parse(q! { (1, 2) }).unwrap(), MyUnnamedRest(1, ::std::vec![2]) ); ::std::assert_eq!( parse(q! { (1, 2,) }).unwrap(), MyUnnamedRest(1, ::std::vec![2]) ); ::std::assert_eq!( parse(q! { (1, 2, 3, 4) }).unwrap(), MyUnnamedRest(1, ::std::vec![2, 3, 4]) ); ::std::assert_eq!( parse(q! { (1, 2, 3, 4, "hello", 6) }).unwrap_err_string(), "expected integer literal" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum MyEmptyEnum {} #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyFlatNamed { j_a: i32, j_b: ::std::string::String, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum MyEnum { A, B(), C(i32), #[deluxe(transparent)] D(bool), E(::std::string::String, f64), F {}, #[deluxe(transparent)] G { pass: ::syn::Path, }, H { s: ::std::string::String, f: f64, }, #[deluxe(flatten)] FlatI { i: ::std::string::String, }, #[deluxe(flatten)] FlatJ { #[deluxe(flatten)] named: MyFlatNamed, }, #[deluxe(skip)] #[allow(dead_code)] K, } #[test] fn parse_enum() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { ( a ) }).unwrap_err_string(), "expected curly braces" ); ::std::assert_eq!(parse(q! { { a } }).unwrap(), MyEnum::A); ::std::assert_eq!(parse(q! { { a() } }).unwrap(), MyEnum::A); ::std::assert_eq!( parse(q! { { a(x = 123) } }).unwrap_err_string(), "unexpected token `x`" ); ::std::assert_eq!(parse(q! { { b() } }).unwrap(), MyEnum::B()); ::std::assert_eq!(parse(q! { { b = () } }).unwrap(), MyEnum::B()); ::std::assert_eq!( parse(q! { { b(x = 123) } }).unwrap_err_string(), "unexpected token `x`" ); ::std::assert_eq!(parse(q! { { c(123) } }).unwrap(), MyEnum::C(123)); ::std::assert_eq!( parse(q! { { c } }).unwrap_err_string(), "unexpected flag, expected `=` or parentheses" ); ::std::assert_eq!( parse(q! { { c = 123 } }).unwrap_err_string(), "expected parentheses" ); ::std::assert_eq!(parse(q! { { d(true) } }).unwrap(), MyEnum::D(true)); ::std::assert_eq!(parse(q! { { d = true } }).unwrap(), MyEnum::D(true)); ::std::assert_eq!(parse(q! { { d } }).unwrap(), MyEnum::D(true)); ::std::assert_eq!( parse(q! { { e("hello", 4.0) } }).unwrap(), MyEnum::E("hello".into(), 4.0), ); ::std::assert_eq!(parse(q! { { f } }).unwrap(), MyEnum::F {}); ::std::assert_eq!(parse(q! { { f() } }).unwrap(), MyEnum::F {}); ::std::assert_eq!(parse(q! { { f = {} } }).unwrap(), MyEnum::F {}); ::std::assert_eq!( parse(q! { { g(themod::theitem) } }).unwrap(), MyEnum::G { pass: ::syn::parse_quote! { themod::theitem } } ); ::std::assert_eq!( parse(q! { { g = themod::theitem } }).unwrap(), MyEnum::G { pass: ::syn::parse_quote! { themod::theitem } } ); ::std::assert_eq!( parse(q! { { h(s = "qwerty", f = 1.0) } }).unwrap(), MyEnum::H { s: "qwerty".into(), f: 1.0 } ); ::std::assert_eq!( parse(q! { { j_a = 123, j_b = "asdf" } }).unwrap(), MyEnum::FlatJ { named: MyFlatNamed { j_a: 123, j_b: "asdf".into(), } }, ); ::std::assert_eq!( parse(q! { { i = "asdf" } }).unwrap(), MyEnum::FlatI { i: "asdf".into() } ); ::std::assert_eq!( parse(q! { { x() } }).unwrap_err_string(), "unknown field `x`, expected one of `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, fields from `FlatJ`", ); ::std::assert_eq!( parse(q! { { k } }).unwrap_err_string(), "unknown field `k`, expected one of `a`, `b`, `c`, `d`, `e`, `f`, `g`, `h`, `i`, fields from `FlatJ`", ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum MySimpleEnum { A, B, C, } #[test] fn parse_simple_enum() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { { a } }).unwrap(), MySimpleEnum::A); ::std::assert_eq!(parse(q! { { b } }).unwrap(), MySimpleEnum::B); ::std::assert_eq!(parse(q! { { c } }).unwrap(), MySimpleEnum::C); ::std::assert_eq!( parse(q! { { a, b } }).unwrap_err_string(), "expected only one enum variant, got `a` and `b`" ); ::std::assert_eq!( parse(q! { { a, c } }).unwrap_err_string(), "expected only one enum variant, got `a` and `c`" ); ::std::assert_eq!( parse(q! { { d } }).unwrap_err_string(), "unknown field `d`, expected one of `a`, `b`, `c`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct StructWith { normal: ::std::string::String, #[deluxe(with = ::deluxe::with::from_str)] str_int: i32, } ::deluxe::define_with_optional!( pub mod custom_int_option, ::deluxe::with::from_str, i32, ); ::deluxe::define_with_collection!( pub mod custom_int_vec, ::deluxe::with::from_str, ::std::vec::Vec, ); ::deluxe::define_with_map!( pub mod custom_int_map, ::deluxe::with::mod_path, ::deluxe::with::from_str, ::std::collections::HashMap<::syn::Path, i32>, ); #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] #[deluxe(transparent(flatten_unnamed, append))] struct StructWithTransparent { #[deluxe(with = custom_int_vec)] int_vec: ::std::vec::Vec, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct StructWithExtended { #[deluxe(with = custom_int_option)] int: ::std::option::Option, #[deluxe(with = custom_int_vec)] int_vec: ::std::vec::Vec, #[deluxe(append, rename = int_append, with = custom_int_vec)] int_vec2: ::std::vec::Vec, #[deluxe(append, default)] int_vec3: StructWithTransparent, #[deluxe(rest, with = custom_int_map)] int_map: ::std::collections::HashMap<::syn::Path, i32>, } #[test] fn parse_with() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { normal = "abc", str_int = "123" } }).unwrap(), StructWith { normal: "abc".into(), str_int: 123 } ); ::std::assert_eq!( parse(q! { { normal = "abc", str_int = 123 } }).unwrap_err_string(), "expected string literal" ); let make_path = |s| ::syn::parse_str::<::syn::Path>(s).unwrap(); let parse = parse_meta::; ::std::assert_eq!( parse(q! { { int = -4, int_vec = ["1", "2"] } }).unwrap_err_string(), "expected string literal" ); ::std::assert_eq!( parse(q! { { int_vec = [1] } }).unwrap_err_string(), "expected string literal" ); ::std::assert_eq!( parse(q! { { int = "-4", int_vec = ["1", "2"] } }).unwrap(), StructWithExtended { int: Some(-4), int_vec: ::std::vec![1, 2], int_vec2: ::std::vec![], int_vec3: Default::default(), int_map: [].into() } ); ::std::assert_eq!( parse(q! { { int_vec = [], int_append = "1", int_append = "2" } }).unwrap(), StructWithExtended { int: None, int_vec: ::std::vec![], int_vec2: ::std::vec![1, 2], int_vec3: Default::default(), int_map: [].into() } ); ::std::assert_eq!( parse(q! { { int_vec = [], int_append = "1", unknown = "2", hello = "3" } }).unwrap(), StructWithExtended { int: None, int_vec: ::std::vec![], int_vec2: ::std::vec![1], int_vec3: Default::default(), int_map: [(make_path("unknown"), 2), (make_path("hello"), 3)].into() } ); ::std::assert_eq!( parse(q! { { int_vec = [], int_vec3 = "1", int_vec3 = "2" } }).unwrap(), StructWithExtended { int: None, int_vec: ::std::vec![], int_vec2: ::std::vec![], int_vec3: StructWithTransparent { int_vec: ::std::vec![1, 2], }, int_map: [].into() } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct StructNames { #[deluxe(rename = sixty_four, default)] renamed: u64, #[deluxe(alias = thirty_two, default)] aliased: u32, #[deluxe(alias = another, alias = another2, default)] many_aliases: u32, #[deluxe(rename = sixteen, alias = another_sixteen, alias = another2_sixteen, default)] alias_renamed: u16, } #[test] fn struct_field_names() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { { sixty_four = 64 } }).unwrap().renamed, 64); ::std::assert_eq!( parse(q! { { renamed = 64 } }).unwrap_err_string(), "unknown field `renamed`" ); ::std::assert_eq!( parse(q! { { sixty_four = 64, sixty_four = 65 } }).unwrap_err_string(), "duplicate attribute for `sixty_four`" ); ::std::assert_eq!( parse(q! { { sixty_four = 64, renamed = 65 } }).unwrap_err_string(), "unknown field `renamed`" ); ::std::assert_eq!(parse(q! { { aliased = 32 } }).unwrap().aliased, 32); ::std::assert_eq!(parse(q! { { thirty_two = 32 } }).unwrap().aliased, 32); ::std::assert_eq!( parse(q! { { aliased = 32, thirty_two = 33 } }).unwrap_err_string(), "duplicate attribute for `aliased`" ); ::std::assert_eq!( parse(q! { { many_aliases = 32 } }).unwrap().many_aliases, 32 ); ::std::assert_eq!(parse(q! { { another = 32 } }).unwrap().many_aliases, 32); ::std::assert_eq!(parse(q! { { another2 = 32 } }).unwrap().many_aliases, 32); ::std::assert_eq!( parse(q! { { many_aliases = 32, another = 33, another2 = 34 } }).unwrap_err_string(), "duplicate attribute for `many_aliases`, duplicate attribute for `many_aliases`" ); ::std::assert_eq!(parse(q! { { sixteen = 16 } }).unwrap().alias_renamed, 16); ::std::assert_eq!( parse(q! { { another_sixteen = 16 } }) .unwrap() .alias_renamed, 16 ); ::std::assert_eq!( parse(q! { { another2_sixteen = 16 } }) .unwrap() .alias_renamed, 16 ); ::std::assert_eq!( parse(q! { { alias_renamed = 16 } }).unwrap_err_string(), "unknown field `alias_renamed`, did you mean `aliased`?" ); ::std::assert_eq!( ::field_names(), &[ "sixty_four", "aliased", "thirty_two", "many_aliases", "another", "another2", "sixteen", "another_sixteen", "another2_sixteen" ] ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum EnumNames { #[deluxe(rename = renamed_a)] A, #[deluxe(alias = alias_b)] B, #[deluxe(alias = another_c, alias = another2_c)] C, #[deluxe(rename = renamed_d, alias = another_d, alias = another2_d)] D, } #[test] fn enum_field_names() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { { renamed_a } }).unwrap(), EnumNames::A); ::std::assert_eq!(parse(q! { { b } }).unwrap(), EnumNames::B); ::std::assert_eq!(parse(q! { { alias_b } }).unwrap(), EnumNames::B); ::std::assert_eq!(parse(q! { { c } }).unwrap(), EnumNames::C); ::std::assert_eq!(parse(q! { { another_c } }).unwrap(), EnumNames::C); ::std::assert_eq!(parse(q! { { another2_c } }).unwrap(), EnumNames::C); ::std::assert_eq!(parse(q! { { renamed_d } }).unwrap(), EnumNames::D); ::std::assert_eq!(parse(q! { { another_d } }).unwrap(), EnumNames::D); ::std::assert_eq!(parse(q! { { another2_d } }).unwrap(), EnumNames::D); ::std::assert_eq!( parse(q! { { a } }).unwrap_err_string(), "unknown field `a`, expected one of `renamed_a`, `b`, `c`, `renamed_d`" ); ::std::assert_eq!( parse(q! { { d } }).unwrap_err_string(), "unknown field `d`, expected one of `renamed_a`, `b`, `c`, `renamed_d`" ); ::std::assert_eq!( ::field_names(), &[ "renamed_a", "b", "alias_b", "c", "another_c", "another2_c", "renamed_d", "another_d", "another2_d", ] ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] #[deluxe(default)] struct StructDefault { value0: i32, #[deluxe(default = 1)] value1: i32, } #[test] fn struct_defaults() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { } }).unwrap(), StructDefault { value0: 0, value1: 1 } ); ::std::assert_eq!( parse(q! { { value0 = -1, value1 = 2 } }).unwrap(), StructDefault { value0: -1, value1: 2 } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(default = Self { value1: 1, value2: 2 })] struct StructDefaultExpr { value1: i32, value2: i32, } #[test] fn struct_default_expr() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { } }).unwrap(), StructDefaultExpr { value1: 1, value2: 2 } ); ::std::assert_eq!( parse(q! { { value1 = 11 } }).unwrap(), StructDefaultExpr { value1: 11, value2: 2 } ); ::std::assert_eq!( parse(q! { { value2 = 22 } }).unwrap(), StructDefaultExpr { value1: 1, value2: 22 } ); ::std::assert_eq!( parse(q! { { value1 = 11, value2 = 22 } }).unwrap(), StructDefaultExpr { value1: 11, value2: 22 } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] struct StructDefaultTuple(i32, #[deluxe(default)] i32); #[test] fn struct_default_tuple() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! {}).unwrap_err_string(), "unexpected end of input, expected parentheses" ); ::std::assert_eq!( parse(q! { () }).unwrap_err_string(), "missing required field 0" ); ::std::assert_eq!(parse(q! { (1) }).unwrap(), StructDefaultTuple(1, 0)); ::std::assert_eq!(parse(q! { (1, 2) }).unwrap(), StructDefaultTuple(1, 2)); ::std::assert_eq!( parse(q! { (1, 2, 3) }).unwrap_err_string(), "unexpected token `3`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(default = Self(1, 2))] struct StructDefaultTupleExpr(i32, i32); #[test] fn struct_default_tuple_expr() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { () }).unwrap(), StructDefaultTupleExpr(1, 2)); ::std::assert_eq!(parse(q! { (3) }).unwrap(), StructDefaultTupleExpr(3, 2)); ::std::assert_eq!(parse(q! { (3,) }).unwrap(), StructDefaultTupleExpr(3, 2)); ::std::assert_eq!(parse(q! { (3, 4) }).unwrap(), StructDefaultTupleExpr(3, 4)); ::std::assert_eq!(parse(q! { (3, 4,) }).unwrap(), StructDefaultTupleExpr(3, 4)); ::std::assert_eq!( parse(q! { (3, 4,,) }).unwrap_err_string(), "unexpected token `,`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct FieldDefaults { #[deluxe(default = MyNewtype(::std::string::String::new()))] name: MyNewtype, #[deluxe(default)] value0: i32, #[deluxe(default = 1)] value1: i32, value: i32, } #[test] fn field_defaults() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { } }).unwrap_err_string(), "missing required field `value`" ); ::std::assert_eq!( parse(q! { { value = 123 } }).unwrap(), FieldDefaults { name: MyNewtype(String::from("")), value0: 0, value1: 1, value: 123, } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] #[deluxe(default)] enum EnumDefault { #[default] A, B, C(#[deluxe(default)] i32), } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(default = Self::A)] enum EnumDefaultExpr { A, B, C, } #[test] fn enum_defaults() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!(parse(q! { { } }).unwrap(), EnumDefault::A); ::std::assert_eq!(parse(q! { { c } }).unwrap(), EnumDefault::C(0)); ::std::assert_eq!(parse(q! { { c() } }).unwrap(), EnumDefault::C(0)); ::std::assert_eq!(parse(q! { { c = () } }).unwrap(), EnumDefault::C(0)); ::std::assert_eq!(parse(q! { { c(1) } }).unwrap(), EnumDefault::C(1)); ::std::assert_eq!(parse(q! { { c(1,) } }).unwrap(), EnumDefault::C(1)); ::std::assert_eq!( parse(q! { { c = (,) } }).unwrap_err_string(), "expected integer literal" ); let parse = parse_meta::; ::std::assert_eq!(parse(q! { { } }).unwrap(), EnumDefaultExpr::A); } use ::deluxe as renamed_deluxe; #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(crate = renamed_deluxe)] struct RenamedCrate(i32); #[test] fn renamed_crate() { let parse = parse_meta::; ::std::assert_eq!(parse(q! { (50) }).unwrap(), RenamedCrate(50)); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(allow_unknown_fields)] struct StructAllowUnknown { value: i32, } #[test] fn struct_allow_unknown() { let parse = parse_meta::; ::std::assert_eq!( parse(q! { { value = 10 } }).unwrap(), StructAllowUnknown { value: 10 } ); ::std::assert_eq!( parse(q! { { value = 10, another = "hello" } }).unwrap(), StructAllowUnknown { value: 10 } ); ::std::assert_eq!( parse( q! { { value = 10, complex = ::c::X + 123 + (Z(Y) % { x[0].a }), another = "hello" } } ) .unwrap(), StructAllowUnknown { value: 10 } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum EnumAllow { Known { value: i32, }, #[deluxe(allow_unknown_fields)] Unknown { value: i32, }, FlattenedKnown { #[deluxe(flatten)] s: MyNamed, }, FlattenedUnknown { #[deluxe(flatten)] s: StructAllowUnknown, }, } #[test] fn enum_allow_unknown() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { known(value(50)) } }).unwrap(), EnumAllow::Known { value: 50 } ); ::std::assert_eq!( parse(q! { { known(value(50)), unknown(value(51)) } }).unwrap_err_string(), "expected only one enum variant, got `known` and `unknown`" ); ::std::assert_eq!( parse(q! { { known(value(50), another("thing")) } }).unwrap_err_string(), "unknown field `another`" ); ::std::assert_eq!( parse(q! { { known(value(50), another("thing")), unknown(value("50")) } }).unwrap_err_string(), "unknown field `another`, expected only one enum variant, got `known` and `unknown`, expected integer literal" ); ::std::assert_eq!( parse(q! { { unknown(value(50)) } }).unwrap(), EnumAllow::Unknown { value: 50 } ); ::std::assert_eq!( parse(q! { { unknown(value(50), another("thing")) } }).unwrap(), EnumAllow::Unknown { value: 50 } ); ::std::assert_eq!( parse(q! { { flattened_known(a(50), b("thing")) } }).unwrap(), EnumAllow::FlattenedKnown { s: MyNamed { a: 50, b: String::from("thing") } } ); ::std::assert_eq!( parse(q! { { flattened_known(a(50), b("thing"), another("two")) } }).unwrap_err_string(), "unknown field `another`" ); ::std::assert_eq!( parse(q! { { flattened_unknown(value(60)) } }).unwrap(), EnumAllow::FlattenedUnknown { s: StructAllowUnknown { value: 60 } } ); ::std::assert_eq!( parse(q! { { flattened_unknown(value(60), another("thing")) } }).unwrap(), EnumAllow::FlattenedUnknown { s: StructAllowUnknown { value: 60 } } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(flatten_named))] struct MyTransparentUnnamedStruct(MyNamed); #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(flatten_named))] struct MyTransparentNamedStruct { named: MyNamed, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(flatten_unnamed, append))] struct MyTransparentUnnamedVec(::std::vec::Vec); #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(flatten_unnamed, append))] struct MyTransparentNamedVec { nums: ::std::vec::Vec, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(rest))] struct MyTransparentUnnamedMap(::std::collections::HashMap<::syn::Path, i32>); #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(transparent(rest))] struct MyTransparentNamedMap { nums: ::std::collections::HashMap<::syn::Path, i32>, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] enum TransparentHolder { A { #[deluxe(flatten)] s: MyTransparentUnnamedStruct, }, B { #[deluxe(flatten)] s: MyTransparentNamedStruct, }, C(#[deluxe(flatten)] MyTransparentUnnamedVec), D(#[deluxe(flatten)] MyTransparentNamedVec), E { #[deluxe(append)] v: MyTransparentUnnamedVec, }, F { #[deluxe(append)] v: MyTransparentNamedVec, }, G { #[deluxe(rest)] r: MyTransparentUnnamedMap, }, H { #[deluxe(rest)] r: MyTransparentNamedMap, }, } #[test] fn transparent_flat() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { a(a(4), b("hello")) } }).unwrap(), TransparentHolder::A { s: MyTransparentUnnamedStruct(MyNamed { a: 4, b: String::from("hello") }) } ); ::std::assert_eq!( parse(q! { { b(a(4), b("hello")) } }).unwrap(), TransparentHolder::B { s: MyTransparentNamedStruct { named: MyNamed { a: 4, b: String::from("hello") } } } ); ::std::assert_eq!( parse(q! { { c } }).unwrap(), TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![])) ); ::std::assert_eq!( parse(q! { { c() } }).unwrap(), TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![])) ); ::std::assert_eq!( parse(q! { { c(1, 2, 3) } }).unwrap(), TransparentHolder::C(MyTransparentUnnamedVec(::std::vec![1, 2, 3])) ); ::std::assert_eq!( parse(q! { { d } }).unwrap(), TransparentHolder::D(MyTransparentNamedVec { nums: ::std::vec![] }) ); ::std::assert_eq!( parse(q! { { d() } }).unwrap(), TransparentHolder::D(MyTransparentNamedVec { nums: ::std::vec![] }) ); ::std::assert_eq!( parse(q! { { d(1, 2, 3) } }).unwrap(), TransparentHolder::D(MyTransparentNamedVec { nums: ::std::vec![1, 2, 3] }) ); ::std::assert_eq!( parse(q! { { e(v(1), v(2), v(3)) } }).unwrap(), TransparentHolder::E { v: MyTransparentUnnamedVec(::std::vec![1, 2, 3]) } ); ::std::assert_eq!( parse(q! { { f(v(1), v(2), v(3)) } }).unwrap(), TransparentHolder::F { v: MyTransparentNamedVec { nums: ::std::vec![1, 2, 3] } } ); let map = [("a", 1), ("b", 2), ("c", 3)] .into_iter() .map(|(k, v)| { let k = ::syn::Ident::new(k, ::proc_macro2::Span::call_site()); let k: ::syn::Path = ::syn::parse_quote! { #k }; (k, v) }) .collect::<::std::collections::HashMap<_, _>>(); ::std::assert_eq!( parse(q! { { g(a(1), b(2), c(3)) } }).unwrap(), TransparentHolder::G { r: MyTransparentUnnamedMap(map.clone()) } ); ::std::assert_eq!( parse(q! { { h(a(1), b(2), c(3)) } }).unwrap(), TransparentHolder::H { r: MyTransparentNamedMap { nums: map } } ); } #[derive(PartialEq, Debug)] struct CustomAppendSum(i32); impl ::deluxe::ParseMetaAppend for CustomAppendSum { fn parse_meta_append<'s, S, I, P>(inputs: &[S], paths: I) -> ::deluxe::Result where S: ::std::borrow::Borrow>, I: ::std::iter::IntoIterator, I::IntoIter: ::std::clone::Clone, P: ::std::convert::AsRef, { use ::std::prelude::v1::*; let mut value = 0; let errors = ::deluxe::Errors::new(); let paths = paths.into_iter(); ::deluxe_core::parse_helpers::parse_struct(inputs, |input, p, pspan| { if paths.clone().any(|path| path.as_ref() == p) { value += ::deluxe_core::parse_helpers::parse_named_meta_item::(input, pspan)?; } else { ::deluxe_core::parse_helpers::skip_meta_item(input); } ::deluxe::Result::Ok(()) })?; errors.check()?; ::deluxe::Result::Ok(Self(value)) } } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct CustomAppend { first: i32, #[deluxe(append)] sum: CustomAppendSum, } #[test] fn custom_append_sum() { let parse = parse_meta::; ::std::assert_eq!( parse(q! { { first = 50, sum = 2, sum = 3 } }).unwrap(), CustomAppend { first: 50, sum: CustomAppendSum(5) } ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct MyOptionalNamed { #[deluxe(default)] a: i32, #[deluxe(default)] b: ::std::string::String, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct PositionalAndNamed( #[deluxe(default)] i32, #[deluxe(default)] i32, #[deluxe(flatten)] MyOptionalNamed, ); #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct NestedPositionalAndNamed( i32, #[deluxe(flatten)] MyUnnamed, #[deluxe(default)] i32, #[deluxe(flatten)] PositionalAndNamed, ); #[test] fn positional_and_named() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { (1) }).unwrap(), PositionalAndNamed(1, 0, MyOptionalNamed { a: 0, b: "".into() }) ); ::std::assert_eq!( parse(q! { (1, 2) }).unwrap(), PositionalAndNamed(1, 2, MyOptionalNamed { a: 0, b: "".into() }) ); ::std::assert_eq!( parse(q! { (1, 2, b = "4" ) }).unwrap(), PositionalAndNamed( 1, 2, MyOptionalNamed { a: 0, b: "4".into() } ) ); ::std::assert_eq!( parse(q! { (1, 2, a = 3, b = "4" ) }).unwrap(), PositionalAndNamed( 1, 2, MyOptionalNamed { a: 3, b: "4".into() } ) ); ::std::assert_eq!( parse(q! { (1, 2, b = "4", a = 3 ) }).unwrap(), PositionalAndNamed( 1, 2, MyOptionalNamed { a: 3, b: "4".into() } ) ); let parse = parse_meta::; ::std::assert_eq!( parse(q! { (1, 2, "3") }).unwrap(), NestedPositionalAndNamed( 1, MyUnnamed(2, "3".into()), 0, PositionalAndNamed(0, 0, MyOptionalNamed { a: 0, b: "".into() }) ) ); ::std::assert_eq!( parse(q! { (1, 2, "3", 4, 5) }).unwrap(), NestedPositionalAndNamed( 1, MyUnnamed(2, "3".into()), 4, PositionalAndNamed(5, 0, MyOptionalNamed { a: 0, b: "".into() }) ) ); ::std::assert_eq!( parse(q! { (1, 2, "3", 4, 5, 6, a = 7, b = "8" ) }).unwrap(), NestedPositionalAndNamed( 1, MyUnnamed(2, "3".into()), 4, PositionalAndNamed( 5, 6, MyOptionalNamed { a: 7, b: "8".into() } ) ) ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] enum KwEnum { #[default] A, B, Const, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct FlattenedEnum { #[deluxe(flatten)] kw: KwEnum, } #[test] fn flattened_enum() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { a } }).unwrap(), FlattenedEnum { kw: KwEnum::A } ); ::std::assert_eq!( parse(q! { { b } }).unwrap(), FlattenedEnum { kw: KwEnum::B } ); ::std::assert_eq!( parse(q! { { const } }).unwrap(), FlattenedEnum { kw: KwEnum::Const } ); ::std::assert_eq!( parse(q! { {} }).unwrap_err_string(), "expected one of `a`, `b`, `const`" ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct FlagStruct { myflag: ::deluxe::Flag, #[deluxe(default)] value: i32, } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] // should always error when encountering the field struct FlagTupleStruct(::deluxe::Flag); #[test] fn flag() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { myflag } }).unwrap(), FlagStruct { myflag: true.into(), value: 0, } ); ::std::assert_eq!( parse(q! { {} }).unwrap(), FlagStruct { myflag: false.into(), value: 0, } ); ::std::assert_eq!( parse(q! { { myflag, value = 123 } }).unwrap(), FlagStruct { myflag: true.into(), value: 123, } ); ::std::assert_eq!( parse(q! { { myflag = true } }).unwrap_err_string(), "unexpected token", ); ::std::assert_eq!( parse(q! { { myflag(true) } }).unwrap_err_string(), "unexpected token", ); let parse = parse_meta::; ::std::assert_eq!( parse(q! { (myflag) }).unwrap_err_string(), "field with type `Flag` can only be a named field with no value", ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(and_then = Self::validate_min, and_then = Self::validate_max)] struct AndThens { a: ::deluxe::SpannedValue, b: i32, } impl AndThens { fn validate_min(self) -> ::deluxe::Result { if *self.a + self.b <= -10 { ::deluxe::Result::Err(::deluxe::Error::new( ::syn::spanned::Spanned::span(&self.a), "sum of a and b must be above -10", )) } else { ::deluxe::Result::Ok(self) } } fn validate_max(self) -> ::deluxe::Result { if *self.a + self.b >= 10 { ::deluxe::Result::Err(::deluxe::Error::new( ::syn::spanned::Spanned::span(&self.a), "sum of a and b must be below 10", )) } else { ::deluxe::Result::Ok(self) } } } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] #[deluxe(and_then = Self::validate_min, and_then = Self::validate_max)] enum AndThensEnum { Values { a: ::deluxe::SpannedValue, b: i32, }, Empty, } impl AndThensEnum { fn validate_min(self) -> ::deluxe::Result { if let Self::Values { a, b } = &self { if **a + *b <= -10 { return ::deluxe::Result::Err(::deluxe::Error::new( ::syn::spanned::Spanned::span(a), "sum of a and b must be above -10", )); } } ::deluxe::Result::Ok(self) } fn validate_max(self) -> ::deluxe::Result { if let Self::Values { a, b } = &self { if **a + *b >= 10 { return ::deluxe::Result::Err(::deluxe::Error::new( ::syn::spanned::Spanned::span(a), "sum of a and b must be below 10", )); } } ::deluxe::Result::Ok(self) } } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] #[deluxe(and_then = Self::validate)] struct OnlyOne { a: ::std::option::Option<::std::string::String>, b: ::std::option::Option<::std::string::String>, } impl OnlyOne { fn validate(self) -> ::deluxe::Result { let errors = ::deluxe::Errors::new(); let Self { a, b } = &self; ::deluxe::validations::only_one!("", &errors, a, b); errors.into_result(self) } } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, Default, )] #[deluxe(and_then = Self::validate)] struct AllOrNone { a: ::std::option::Option<::std::string::String>, b: ::std::option::Option<::std::string::String>, } impl AllOrNone { fn validate(self) -> ::deluxe::Result { let errors = ::deluxe::Errors::new(); let Self { a, b } = &self; ::deluxe::validations::all_or_none!("", &errors, a, b); errors.into_result(self) } } #[test] fn and_then() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { a = 5, b = 4 } }).unwrap(), AndThens { a: 5.into(), b: 4 } ); ::std::assert_eq!( parse(q! { { a = -5, b = -6 } }).unwrap_err_string(), "sum of a and b must be above -10", ); ::std::assert_eq!( parse(q! { { a = 5, b = 6 } }).unwrap_err_string(), "sum of a and b must be below 10", ); let parse = parse_meta::; ::std::assert_eq!(parse(q! { { empty } }).unwrap(), AndThensEnum::Empty); ::std::assert_eq!( parse(q! { { values(a = 5, b = 4) } }).unwrap(), AndThensEnum::Values { a: 5.into(), b: 4 } ); ::std::assert_eq!( parse(q! { { values(a = -5, b = -6) } }).unwrap_err_string(), "sum of a and b must be above -10", ); ::std::assert_eq!( parse(q! { { values(a = 5, b = 6) } }).unwrap_err_string(), "sum of a and b must be below 10", ); let parse = parse_meta::; ::std::assert_eq!(parse(q! { {} }).unwrap(), OnlyOne::default()); ::std::assert_eq!( parse(q! { {a("a")} }).unwrap(), OnlyOne { a: Some("a".into()), b: None } ); ::std::assert_eq!( parse(q! { {b("b")} }).unwrap(), OnlyOne { a: None, b: Some("b".into()), } ); // error appears twice, once on each attribute ::std::assert_eq!( parse(q! { {a("a"), b("b")} }).unwrap_err_string(), "only one of `a`, `b` is allowed, only one of `a`, `b` is allowed", ); let parse = parse_meta::; ::std::assert_eq!(parse(q! { {} }).unwrap(), AllOrNone::default()); ::std::assert_eq!( parse(q! { {a("a"), b("b")} }).unwrap(), AllOrNone { a: Some("a".into()), b: Some("b".into()), } ); ::std::assert_eq!( parse(q! { {a("a")} }).unwrap_err_string(), "`b` must also be set in order to use `a`", ); ::std::assert_eq!( parse(q! { {b("b")} }).unwrap_err_string(), "`a` must also be set in order to use `b`", ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct FieldTransforms { #[deluxe(map = |x: ::syn::Ident| ::std::string::ToString::to_string(&x))] ident: ::std::string::String, #[deluxe(map = |x: ::syn::Ident| ::std::string::ToString::to_string(&x))] #[deluxe(map = |s| ::std::format!("prefix_{s}"))] prefixed_ident: ::std::string::String, #[deluxe(and_then = |u: u32| >::try_from(u) .map_err(|_| ::syn::Error::new(::proc_macro2::Span::call_site(), "my_int too big")))] my_int: u16, #[deluxe(and_then = |u: u32| >::try_from(u) .map_err(|_| ::syn::Error::new(::proc_macro2::Span::call_site(), "is_one too big")))] #[deluxe(map = |u| u == 1)] is_one: bool, } #[test] fn field_transforms() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { ident = hello, prefixed_ident = world, my_int = 200, is_one = 1, } }).unwrap(), FieldTransforms { ident: String::from("hello"), prefixed_ident: String::from("prefix_world"), my_int: 200, is_one: true } ); ::std::assert_eq!( parse(q! { { ident = goodbye, prefixed_ident = moon, my_int = 300, is_one = 123, } }) .unwrap(), FieldTransforms { ident: String::from("goodbye"), prefixed_ident: String::from("prefix_moon"), my_int: 300, is_one: false } ); ::std::assert_eq!( parse(q! { { ident = hello, prefixed_ident = world, my_int = 100000, is_one = 1, } }) .unwrap_err_string(), "my_int too big", ); ::std::assert_eq!( parse(q! { { ident = hello, prefixed_ident = world, my_int = 200000, is_one = 100000, } }) .unwrap_err_string(), "my_int too big, is_one too big", ); } #[derive( ::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem, PartialEq, Debug, )] struct RawIdentKeys { r#struct: ::syn::Type, r#trait: ::syn::Type, } #[test] fn raw_ident_keys() { use ::std::prelude::v1::*; let parse = parse_meta::; ::std::assert_eq!( parse(q! { { struct = A, trait = B } }).unwrap(), RawIdentKeys { r#struct: ::syn::parse_quote! { A }, r#trait: ::syn::parse_quote! { B }, } ); } #[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)] struct NoDebugInner { _a: i32, _b: ::std::string::String, } #[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)] struct NoDebug { _a: i32, _b: ::std::string::String, _c: NoDebugInner, } #[derive(::deluxe::ParseAttributes, ::deluxe::ExtractAttributes, ::deluxe::ParseMetaItem)] enum NoDebugEnum { _A(NoDebug), _B(NoDebugInner), }