#proc-macro-attributes #macro-derive #structs #struct-fields #parser #error #validation

darling

用于在实现自定义 derive 时将属性读入结构体的 proc-macro 库

58 个版本

0.20.10 2024 年 7 月 9 日
0.20.8 2024 年 2 月 23 日
0.20.3 2023 年 7 月 12 日
0.14.4 2023 年 3 月 9 日
0.2.0 2017 年 6 月 19 日

19 in Rust 模式

Download history 1392348/week @ 2024-05-04 1504908/week @ 2024-05-11 1523295/week @ 2024-05-18 1498305/week @ 2024-05-25 1659515/week @ 2024-06-01 1639846/week @ 2024-06-08 1612958/week @ 2024-06-15 1617297/week @ 2024-06-22 1466074/week @ 2024-06-29 1653534/week @ 2024-07-06 1636646/week @ 2024-07-13 1693814/week @ 2024-07-20 1671589/week @ 2024-07-27 1700920/week @ 2024-08-03 1736469/week @ 2024-08-10 1503440/week @ 2024-08-17

6,899,475 每月下载量
用于 7,601 包(602 个直接使用)

MIT 许可证

325KB
6.5K SLoC

darling

Build Status Latest Version Rustc Version 1.56+

darling 是一个用于 proc-macro 作者的包,它允许将属性解析到结构体中。它在内部和 API 方面都受到了 serde 的极大启发。

优点

  • 易于声明性解析宏输入 - 以最少的投资时间使您的 proc-macro 具有高度可控性。
  • 出色的验证和错误处理,无需额外工作。当您的 proc-macro 用户犯错误时,darling 确保他们在源代码的正确位置获得错误标记,并提供“你是否指的是”的拼写建议。

用法

darling 提供了一组可以派生或手动实现的特质。

  1. FromMeta 用于从属性中的元项中提取值。实现可能是许多库的可重用,就像 FromStrserde::Deserialize 一样。为原始数据类型、一些 std 类型和一些 syn 类型提供了特质实现。
  2. FromDeriveInput 由每个依赖于 darling 的 proc-macro 包实现或派生。这是输入解析的根;它可以访问目标类型的身份、泛型和可见性,并可以指定应从输入 AST 解析或传递哪些属性名称。
  3. FromField 由每个依赖于 darling 的 proc-macro 包实现或派生。实现此特质的结构体将访问字段的身份(如果存在)、类型和可见性。
  4. FromVariant 由每个依赖于 darling 的 proc-macro 包实现或派生。实现此特质的结构体将访问变体的身份和内容,可以像任何其他 darling 输入一样进行转换。
  5. FromAttributesFromDeriveInputFromFieldFromVariant 等更具体特质的一个低级版本。使用此特质的结构体将获得一个元项提取器和错误收集器,它适用于任何语法元素,包括特质、特质项和函数。这对于非 derive 过程宏非常有用。

附加模块

  • darling::ast 提供了表示抽象语法树的泛型类型。
  • darling::usage 提供了用于确定结构体或枚举中类型参数和生命周期使用位置的特质和函数。
  • darling::util 提供了具有特殊 FromMeta 实现的辅助类型,例如 PathList

示例

use darling::{FromDeriveInput, FromMeta};

#[derive(Default, FromMeta)]
#[darling(default)]
pub struct Lorem {
    #[darling(rename = "sit")]
    ipsum: bool,
    dolor: Option<String>,
}

#[derive(FromDeriveInput)]
#[darling(attributes(my_crate), forward_attrs(allow, doc, cfg))]
pub struct MyTraitOpts {
    ident: syn::Ident,
    attrs: Vec<syn::Attribute>,
    lorem: Lorem,
}

上面的代码将能够解析以下输入

/// A doc comment which will be available in `MyTraitOpts::attrs`.
#[derive(MyTrait)]
#[my_crate(lorem(dolor = "Hello", sit))]
pub struct ConsumingType;

属性宏

支持非 derive 属性宏。要解析属性宏的参数,在参数接收类型上 derive FromMeta,然后使用 darling::ast::NestedMeta::parse_meta_list 将参数 TokenStream 转换为 Vec<NestedMeta>,然后将其传递给接收参数类型的 derive from_list 方法。这将生成一个普通的 darling::Result<T>,它可以像解析 DeriveInput 的结果一样使用。

宏代码

use darling::{Error, FromMeta};
use darling::ast::NestedMeta;
use syn::ItemFn;
use proc_macro::TokenStream;

#[derive(Debug, FromMeta)]
struct MacroArgs {
    #[darling(default)]
    timeout_ms: Option<u16>,
    path: String,
}

#[proc_macro_attribute]
pub fn your_attr(args: TokenStream, input: TokenStream) -> TokenStream {
    let attr_args = match NestedMeta::parse_meta_list(args.into()) {
        Ok(v) => v,
        Err(e) => { return TokenStream::from(Error::from(e).write_errors()); }
    };
    let _input = syn::parse_macro_input!(input as ItemFn);

    let _args = match MacroArgs::from_list(&attr_args) {
        Ok(v) => v,
        Err(e) => { return TokenStream::from(e.write_errors()); }
    };

    // do things with `args`
    unimplemented!()
}

消费代码

use your_crate::your_attr;

#[your_attr(path = "hello", timeout_ms = 15)]
fn do_stuff() {
    println!("Hello");
}

特性

Darling 的特性是为了在现实世界的项目中表现良好而构建的。

  • 默认值:支持结构体和字段级别的默认值,使用与 serde 相同的路径语法。此外,Option<T>darling::util::Flag 字段是内建的可选;您不需要为这些声明 #[darling(default)]
  • 字段重命名:字段在用法和底层代码中可以有不同的名称。
  • 自动填充字段:从 FromDeriveInputFromField 推导的结构体可以声明名为 identvistyattrsgenerics 的属性,以自动从输入 AST 中获取匹配值的副本。FromDeriveInput 还公开了 data 以访问推导类型的主体,而 FromVariant 公开了 fields
    • 转发属性转换:您可以在attrs字段中添加 #[darling(with=path)] 来使用自定义函数在将属性提供给您的结构体之前进行转换。函数签名是 fn(Vec<Attribute>) -> darling::Result<T>,其中 T 是您为 attrs 字段声明的类型。从这个函数返回错误将与其他所有解析错误一起传播。
  • 映射函数:使用 #[darling(map="path")]#[darling(and_then="path")] 来指定一个函数,该函数在解析元项字段的结果上运行。这可以改变返回类型,从而使您能够将解析到的中间形式转换为在结构体中需要的类型。
  • 跳过字段:使用 #[darling(skip)] 标记不应从属性元项中读取的字段。
  • 多出现字段:在 Vec 字段上使用 #[darling(multiple)] 允许该字段在元项中多次出现。每个出现都将推入 Vec
  • 跨度访问:在一个结构体中使用 darling::util::SpannedValue 来获取对那个元项源代码跨度的访问。这可以用来发出指向您过程宏中特定字段的警告。此外,您可以使用 darling::Error::write_errors 在大多数情况下自动获得精确的错误位置详细信息。
  • "你可能想说的是"建议:派生 darling 特性实现中的编译错误包括对拼写错误的字段的建议。
  • 结构扁平化:使用 #[darling(flatten)] 来在向用户展示元项时删除一层结构。未知于父结构的字段将被转发到 flatten 字段。

形状验证

一些过程宏仅在结构体上工作,而另一些需要枚举,其变体是单元或新类型变体。Darling 使此类验证变得极为简单。在派生自 FromDeriveInput 的接收器上添加 #[darling(supports(...))],然后列出您的宏应接受的形状。

名称 描述
any 接受任何内容
struct_any 接受任何结构体
struct_named 接受具有命名字段的结构体,例如 struct Example { field: String }
struct_newtype 接受新类型结构体,例如 struct Example(String)
struct_tuple 接受元组结构体,例如 struct Example(String, String)
struct_unit 接受单元结构体,例如 struct Example;
enum_any 接受任何枚举
enum_named 接受具有命名字段的枚举变体
enum_newtype 接受新类型枚举变体
enum_tuple 接受元组枚举变体
enum_unit 接受单元枚举变体

每个都是累加的,因此列出 #[darling(supports(struct_any, enum_newtype))] 将接受所有结构和任何枚举,其中每个变体都是新类型变体。

这也可以在派生 FromVariant 时使用,不需要 enum_ 前缀。

依赖关系

~245–690KB
~16K SLoC