Rust 每日一库 —— Darling

Darling

1. 名词解释

field (字段)是指属于一个对象或数据结构的一个数据成员,在宏编程时我们往往期望获得字段的名词、字段的类型、以及额外的自定义属性

2. 使用原因

期望在过程宏中解析syn::DeriveInput得出申明性属性。
例1: 结构体中的 field ---> bar 中的 skip 属性为 true

#[derive(Lorem)]
pub struct Foo {
    #[lorem(skip)]
    bar: bool,
    baz: i64,
}

例2: 结构体本身具有一个属性 field 为 inner

#[allow(unused)]
#[derive(Debug, AutoDeref)]
#[deref(field = "inner")]
pub struct RespBulkString {
    inner: String,
    nothing: (),
}

3. 使用 Darling 的一般姿势,以 极客时间Rust auto_deref 为例

为结构体 RespBulkString 自动实现

#[allow(unused)]
#[derive(Debug, AutoDeref)]
#[deref(field = "inner")]
pub struct RespBulkString {
    inner: String,
    nothing: (),
}

为结构体 RespBulkString 自动实现

impl std::ops::Deref for RespBulkString {
    type Target = String;
    fn deref(&self) -> &Self::Target {
        &self.inner
    }
}
impl std::ops::DerefMut for RespBulkString {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.inner
    }
}

3.1 在 lib.rs 中对外暴露 AutoDeref

#[proc_macro_derive(AutoDeref, attributes(deref))]
pub fn derive_auto_deref(input: TokenStream) -> TokenStream {
    let input = syn::parse_macro_input!(input as DeriveInput);
    println!("{:#?}", input);

    process_auto_deref(input).into()
}

3.2 编写转换函数 process_auto_deref

// 参数为 DeriveInput
pub(crate) fn process_auto_deref(input: DeriveInput) -> TokenStream {
}

3.3 定义 AutoDeref 的结构体

描述文本
// 使用 FromDeriveInput 宏自动实现 FromDeriveInput
//  AutoDeref 拥有函数  fn from_derive_input(input: &DeriveInput) -> Result<Self, Error>,用于解析 syn::DeriveInput
#[derive(Debug, FromDeriveInput)]
#[darling(attributes(deref))]
struct AutoDeref {
    ident: syn::Ident,
    generics: syn::Generics,
    // Data 为 enum,前者代表使用 AutoRef 宏的是 enum 类型 —— 与事实不符
    //                       后者代表使用 AutoRef 宏的是 struct 类型
    data: Data<(), AutoDerefField>,
    #[darling(default)]
    field: Option<syn::Ident>,
    #[darling(default)]
    mutable: bool,
}

3.4 定义 AutoDerefField,AutoDeref 中的 data 对应多个 AutoDerefField

描述文本
#[derive(Debug, FromField)]
struct AutoDerefField {
    ident: Option<syn::Ident>,
    ty: syn::Type,
}

4. 拓展

#[derive(Lorem)]
pub struct Foo {
    #[lorem(skip)]
    bar: bool,
    baz: i64,
}

当中的 attributes 同样适用于struct 中的 field 官方示例

#[derive(Debug, FromField)]
#[darling(attributes(lorem))]
pub struct LoremField {
    ident: Option<Ident>,
    ty: Type,
    #[darling(default)]
    skip: bool,
}

#[derive(Debug, FromDeriveInput)]
#[darling(attributes(lorem), supports(struct_named))]
pub struct Lorem {
    ident: Ident,
    data: ast::Data<util::Ignored, LoremField>,
}
posted @ 2024-05-20 21:44  TopWay2Die  阅读(265)  评论(0)    收藏  举报