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 日 |
#446 在 过程宏 中
6,901,366 每月下载量
在 7,603 个 Crates 中使用 (4 直接使用)
305KB
7K SLoC
Darling
darling 是一个用于过程宏作者的 crate,它允许将属性解析到结构体中。在内部和 API 方面都受到了 serde 的极大启发。
优势
- 易于声明性解析宏输入 - 以最少的时间投入使您的过程宏高度可控。
- 出色的验证和错误处理,无需额外工作。当您的过程宏用户犯错时,
darling确保他们在源代码的适当位置获得错误标记,并提供“你是指”的建议以纠正拼写错误的字段。
使用方法
darling 提供了一系列可以派生或手动实现的 trait。
FromMeta用于从属性中的元项中提取值。实现可能是许多库可重用的,类似于FromStr或serde::Deserialize。为原始类型、一些 std 类型和一些syn类型提供了 trait 实现。FromDeriveInput由每个依赖于darling的过程宏 crate 实现。这是输入解析的根;它获取对目标类型的身份、泛型和可见性的访问,并可以指定应从输入 AST 解析或转发哪些属性名称。FromField由每个依赖于darling的过程宏 crate 实现。实现此 trait 的结构体将获取对字段身份(如果存在)、类型和可见性的访问。FromVariant由每个依赖darling的 proc-macro 包实现或派生。派生此特性的结构体将能够访问变体的身份和内容,这可以像任何其他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来访问该元项的源代码跨度。这可以用来发出指向您的 proc 宏中特定字段的警告。此外,您还可以使用darling::Error::write_errors在大多数情况下自动获取精确的错误位置详细信息。 - "你可能想"建议:从派生的 darling 特性实现中编译的错误包括对拼写错误的字段的建议。
- 结构扁平化:使用
#[darling(flatten)]来在向用户展示元项时移除一层结构。未知于父结构的字段将被转发到flatten字段。
形状验证
一些 proc-macros 只在结构体上工作,而另一些需要枚举,其变体为单元或 newtype 变体。Darling 使此类验证变得非常简单。在派生自 FromDeriveInput 的接收器上添加 #[darling(supports(...))],然后列出您的宏应接受的形状。
| 名称 | 描述 |
|---|---|
any |
接受任何内容 |
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–740KB
~17K SLoC