Reputation: 58805
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?
Upvotes: 4
Views: 2023
Reputation: 4603
There is a way to do this, using darling::util::Override
. I've never had a great name for this particular utility, so I'm going to add this exact snippet as an example, and am interested in having a discussion on GH for a name that people are more likely to find.
Upvotes: 2
Reputation: 382334
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());
}
Upvotes: 5