带有“tag”属性的proc_macro_derive

问题描述 投票:0回答:1

我正在尝试实现一个如下所示的派生特征:

#[derive(Cacheable)]
#[cacheable(directory = "path/in/cache")]
pub struct Something {
    #[cacheable(id)]
    pub id: String
}

其中

id
只是一个用于唯一存储数据的字段。只有其中一个字段应标有
id
,并且没有任何与之关联的数据。我们只需要字段的名称。例如该特征具有
fn id() -> String { return self.#id_field.to_string() }

我拥有它,这样我就可以使用豪华库提取

directory
,但我不知道如何获取
id
标签。

fn cacheable_derive_impl(
    item: proc_macro2::TokenStream,
) -> deluxe::Result<proc_macro2::TokenStream> {
    // parse
    let mut ast: syn::DeriveInput = syn::parse2(item)?;

    // extract struct attributes
    let CacheableAttributes { directory } = deluxe::extract_attributes(&mut ast)?;

    // extract field attributes
    // Need to get the single field marked with the id attribute
    let id = if let syn::Data::Struct(s) = &mut ast.data //??
...
}

我发现的所有示例似乎都在尝试提取属性的值,或者在所有字段上都有该属性。

那么问题是,如何获取字段名称并在定义中使用它?

rust
1个回答
0
投票

我使用 parse_nested_meta 找到了答案:

    // extract field attributes
    // Need to get the single field marked with the id attribute
    let id_field = if let syn::Data::Struct(s) = &ast.data {
        s.fields
            .iter()
            .find(|field| {
                field.attrs.iter().any(|attr| {
                    let mut is_id = false;
                    if attr.path().is_ident("cacheable") {
                        attr.parse_nested_meta(|meta| {
                            if meta.path.is_ident("id") {
                                is_id = true;
                            }
                            Ok(())
                        })
                        .unwrap();
                    }
                    is_id
                })
            })
            .map(|field| field.ident.as_ref().unwrap().to_owned())
    } else {
        None
    }
    .ok_or_else(|| syn::Error::new_spanned(&ast, "No field with 'id' attribute found"))?;

我对它看起来有多复杂并不完全满意,但至少它有效。

© www.soinside.com 2019 - 2024. All rights reserved.