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日 |
1809 在 过程宏 中排名
6,986,796 每月下载量
用于 7,465 个crate(2个直接使用)
295KB
6.5K SLoC
Darling
darling
是一个用于过程宏作者的crate,它允许将属性解析到结构体中。它在内部和API方面都深受 serde
的启发。
优点
- 易于声明性解析宏输入 - 用最少的投资时间让您的过程宏高度可控。
- 出色的验证和错误处理,无需额外工作。当您的过程宏用户犯错时,
darling
确保他们在源代码的正确位置获得错误标记,并提供“您是否想”的拼写错误字段建议。
使用方法
darling
提供了一组可以派生或手动实现的特质。
FromMeta
用于从属性中的元项中提取值。实现可能对许多库都是可重用的,就像FromStr
或serde::Deserialize
一样。为原始数据类型、一些 std 类型以及一些syn
类型提供了特质实现。FromDeriveInput
由每个依赖darling
的过程宏crate实现或派生。这是输入解析的根;它获取对目标类型的身份、泛型和可见性的访问,并可以指定哪些属性名称应从输入AST解析或转发。FromField
由每个依赖于darling
的 proc-macro crate 实现。从该特性派生的结构体将能够访问字段的标识(如果存在)、类型和可见性。FromVariant
由每个依赖于darling
的 proc-macro crate 实现。从该特性派生的结构体将能够访问变体的标识和内容,这些内容可以像任何其他darling
输入一样进行转换。FromAttributes
是FromDeriveInput
、FromField
和FromVariant
特性的更具体版本。从该特性派生的结构体将获得一个元项提取器和错误收集器,它适用于任何语法元素,包括特性和函数。这对于非 derive proc-macro 很有用。
附加模块
darling::ast
提供了表示抽象语法树 (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 属性宏。为了解析属性宏的参数,在参数接收器类型上派生 FromMeta
,然后使用 darling::ast::NestedMeta::parse_meta_list
将参数 TokenStream
转换为 Vec<NestedMeta>
,然后将其传递到派生类型的 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
。- 转发属性的转换:您可以将
#[darling(with=path)]
添加到attrs
字段中,以便在将转发属性提供给您的结构体之前使用自定义函数来转换这些属性。该函数签名是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
字段。
形状验证
一些proc-macros只能在结构体上工作,而另一些则需要枚举,其变体是单元或newtype变体。Darling使得此类验证变得极其简单。在派生自FromDeriveInput
的接收器上,添加#[darling(supports(...))]
并然后列出您的宏应接受的形状。
名称 | 描述 |
---|---|
任何 |
接受任何东西 |
struct_any |
接受任何结构体 |
struct_named |
接受具有命名字段的结构体,例如 struct Example { field: String } |
struct_newtype |
接受newtype结构体,例如 struct Example(String) |
struct_tuple |
接受元组结构体,例如 struct Example(String, String) |
struct_unit |
接受单元结构体,例如 struct Example; |
enum_any |
接受任何枚举 |
enum_named |
接受具有命名字段的枚举变体 |
enum_newtype |
接受newtype枚举变体 |
enum_tuple |
接受元组枚举变体 |
enum_unit |
接受单元枚举变体 |
每个都是累加的,所以列出#[darling(supports(struct_any, enum_newtype))]
将接受所有结构体和任何枚举,其中每个变体都是newtype变体。
这也可以在派生FromVariant
时使用,无需使用enum_
前缀。
依赖项
~280–730KB
~17K SLoC