I'm trying to parse an attribute with darling, and I want to support the following usages:
// att not specified
#[derive(MyTrait)]
struct Foo(u64);
// att specified without an argument
#[derive(MyTrait)]
#[myderive(att)]
struct Foo(u64);
// att specified with an argument
#[derive(MyTrait)]
#[myderive(att(value = "String"))]
struct Foo(u64);
These are my types:
#[derive(FromDeriveInput)]
#[darling(attributes(myderive))]
struct MyDeriveInput {
#[darling(default)]
att: Option<MyAttr>,
}
#[derive(FromMeta, Default)]
struct MyAttr {
#[darling(default)]
value: Option<Path>,
}
And a test:
#[test]
fn test() {
let derive_input = syn::parse_str(
r#"
#[derive(MyTrait)]
#[myderive(att)]
struct Foo(u64);
"#,
)
.unwrap();
let parsed: MyDeriveInput = FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert!(parsed.att.is_some());
}
I get this error:
thread 'test' panicked at 'called `Result::unwrap()` on an `Err` value:
Error { kind: UnexpectedFormat("word"), locations: ["att"], span: Some(Span) }'
I get the same error if I specify att
, regardless of whether value
is specified.
Is this possible? If so, what structure does darling expect to parse this into?
The syntax for the derive doesn't exactly work this way for attributes values which are structs.
If you want to specify there's an att
but a default one, you should set it as att()
.
Here's a fixed complete code and test units:
extern crate proc_macro;
extern crate syn;
use {
darling::*,
std::path::*,
};
#[derive(FromMeta)]
struct MyAttr {
#[darling(default)]
value: Option<String>, // I dunno what was your "Path" so I've put String
}
#[derive(FromDeriveInput, Default)]
#[darling(attributes(myderive))]
struct MyTrait {
#[darling(default)]
att: Option<MyAttr>,
}
#[test]
fn test() {
// with specified MyAttr:
let derive_input = syn::parse_str(
r#"
#[derive(MyTrait)]
#[myderive(att(value = "test"))]
struct Foo(u64);
"#,
)
.unwrap();
let parsed: MyTrait = FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert!(parsed.att.is_some());
// with default MyAttr:
let derive_input = syn::parse_str(
r#"
#[derive(MyTrait)]
#[myderive(att())]
struct Foo(u64);
"#,
)
.unwrap();
let parsed: MyTrait = FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert!(parsed.att.is_some());
// with no MyAttr:
let derive_input = syn::parse_str(
r#"
#[derive(MyTrait)]
#[myderive()]
struct Foo(u64);
"#,
)
.unwrap();
let parsed: MyTrait = FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert!(parsed.att.is_none());
// with no myderive
let derive_input = syn::parse_str(
r#"
#[derive(MyTrait)]
struct Foo(u64);
"#,
)
.unwrap();
let parsed: MyTrait = FromDeriveInput::from_derive_input(&derive_input).unwrap();
assert!(parsed.att.is_none());
}