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 模式
6,899,475 每月下载量
用于 7,601 个 包(602 个直接使用)
325KB
6.5K SLoC
darling
darling
是一个用于 proc-macro 作者的包,它允许将属性解析到结构体中。它在内部和 API 方面都受到了 serde
的极大启发。
优点
- 易于声明性解析宏输入 - 以最少的投资时间使您的 proc-macro 具有高度可控性。
- 出色的验证和错误处理,无需额外工作。当您的 proc-macro 用户犯错误时,
darling
确保他们在源代码的正确位置获得错误标记,并提供“你是否指的是”的拼写建议。
用法
darling
提供了一组可以派生或手动实现的特质。
FromMeta
用于从属性中的元项中提取值。实现可能是许多库的可重用,就像FromStr
或serde::Deserialize
一样。为原始数据类型、一些 std 类型和一些syn
类型提供了特质实现。FromDeriveInput
由每个依赖于darling
的 proc-macro 包实现或派生。这是输入解析的根;它可以访问目标类型的身份、泛型和可见性,并可以指定应从输入 AST 解析或传递哪些属性名称。FromField
由每个依赖于darling
的 proc-macro 包实现或派生。实现此特质的结构体将访问字段的身份(如果存在)、类型和可见性。FromVariant
由每个依赖于darling
的 proc-macro 包实现或派生。实现此特质的结构体将访问变体的身份和内容,可以像任何其他darling
输入一样进行转换。FromAttributes
是FromDeriveInput
、FromField
和FromVariant
等更具体特质的一个低级版本。使用此特质的结构体将获得一个元项提取器和错误收集器,它适用于任何语法元素,包括特质、特质项和函数。这对于非 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)]
。 - 字段重命名:字段在用法和底层代码中可以有不同的名称。
- 自动填充字段:从
FromDeriveInput
和FromField
推导的结构体可以声明名为ident
、vis
、ty
、attrs
和generics
的属性,以自动从输入 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