TedDriggs / darling

A Rust proc-macro attribute parser

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Add example for how to do Ident style MetaList values in the nested meta list

leighmcculloch opened this issue · comments

It isn't clear how to use darling to do the following. I think it's possible, but can't work out how to configure darling to do it, so maybe that means it's not possible.

#[my_attribute(MyOtherType, some_config = "maybe")]
struct MyType {
    // ...
}

The MyOtherType is a MetaList, which is one of the types of NestedMeta::Meta.

Ah, so I don't think this is supported, at least according to:

fn from_meta(item: &Meta) -> Result<Self> {
(match *item {
Meta::Path(_) => Self::from_word(),
Meta::List(ref value) => Self::from_list(

The MyOtherType above is a Path, and it appears Paths are just passed to from_word() that is always unsupported. The value of the path is discarded.

You'd need a custom implementation of FromMeta for this, which would slice off the first term and then run the remainder through some sort of "options" struct to collect the key-value pairs.

This also was deliberately not a goal of darling - at the time darling was built, only cfg_attr worked that way in the standard library and it wasn't common in 3rd-party crates. I'm still not sure how I feel about the proliferation of "positional followed by keyword args in macros" but given that FromMeta does allow a manual implementation to achieve the desired result I'm disinclined to natively support it.

How would this work for a derive macro? Like if my intended usage was:

#[derive(my_derive::MyTrait)]
#[magic(MagicPath)]
struct TestOne;

So I create a FromDeriveInput struct:

#[derive(FromDeriveInput)]
#[darling(attributes(magic))]
struct MyTraitDerive {
    ident: syn::Ident,
    vis: syn::Visibility,
    generics: syn::Generics,
    magic: MagicSpec,
}

The MagicSpec (which I just want to be a path) looks like:

struct MagicSpec(syn::Path);

impl FromMeta for MagicSpec {
    fn from_meta(item: &syn::Meta) -> darling::Result<Self> {
        todo!("Meta: {:?}", item)
    }
}

Trying to compile my expected usage never even reaches the from_meta() method on MagicSpec:

error: Unknown field: `MagicPath`
  --> tests/compilation/myderive_build.rs:14:9
   |
14 | #[magic(MagicPath))]
   |         ^^^^^^^^^

How do I actually "connect" the magic attribute to MagicSpec::from_meta()?

The issue here is that you've now got two layers of "magic", so the expected input would become...

#[magic(magic(MagicPath))]

The outer magic is the attribute name, and the inner is the field name.

If you just have a single attribute that you want read as a list, I'd probably suggest using forward_attrs and then having a custom and_then method to handle the extraction of that into the field on the parent.