TedDriggs / darling

A Rust proc-macro attribute parser

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Recognising generic types with `PathList`

wainwrightmark opened this issue · comments

Hi. I'm trying to use PathList in a FromDeriveInput struct. It works great for normal types but doesn't work for generic types.

My attribute looks like

#[derive(FromDeriveInput, Default)]
#[darling(default, attributes(store))]
struct Opts {
    listener: PathList
}

and I'm parsing it with

let opts = Opts::from_derive_input(&input).expect("Invalid options");

It works fine for code like this

#[derive( Store)]
#[store(listener(MyListener1, MyListener2))]
struct State {
    count: u32,
}

but not for generic types

#[derive( Store)]
#[store(listener(HistoryListener::<State>))]
struct State {
    count: u32,
}

gives

proc-macro derive panicked
message: Invalid options: Error { kind: Custom("expected path segment after `::`"), locations: ["listener"], span: Some(#0 bytes(156..157)) }

Doing it without the tubofish #[store(listener(HistoryListener<State>))] gives

proc-macro derive panicked
message: Invalid options: Error { kind: Custom("expected `,`"), locations: ["listener"], span: Some(#0 bytes(154..155)) }

Am I doing something wrong? Is there a way around this? Using vec<Path> with the multiple attribute does work but the syntax you have to pass in is different and I don't like it as much.

That seems to be the result of how it's implemented; a PathList is actually a sequence of valueless Path children in a NestedMeta (source). I think you'll need to do something custom to accept type parameters there, since syn wouldn't support that natively.

The version without a turbofish is a Type but not a Path, so I’m not surprised to see an error from that one.

You could file a syn issue to see if there’s any appetite there for allowing non-ident parts in these paths, but unless the support is added there this will continue not to work in darling.

One random idea for you - could you maybe make this field take a TypeTuple? Then the syntax would be…

#[store(listener = (HistoryListener<State>, OtherListener<State>))]

You might want to name the field listeners in that case to make the plurality a bit more obvious.