12个版本
0.1.11 | 2021年11月10日 |
---|---|
0.1.10 | 2020年12月12日 |
0.1.9 | 2020年9月5日 |
0.1.7 | 2020年6月16日 |
0.1.0 | 2018年12月24日 |
#22 in #submit
30,535次每月下载
7KB
56 行
类型化分布式插件注册
这个包提供了一种将插件注册表设置到应用程序中,允许从任何源文件中注册插件的方法。不需要一个包含所有插件的中央列表。
[dependencies]
inventory = "0.3"
支持rustc 1.62+
示例
假设我们正在编写一个命令行标志库,并希望允许应用程序中的任何源文件注册与其相关的命令行标志。
这是gflags使用的标志注册风格,与维护单个中央标志列表相比,更适合大规模开发,因为中央列表会成为成千上万的开发者同时开发的应用程序中合并冲突的无尽源泉。
实例化插件注册表
我们使用一个struct Flag
作为插件类型,它将包含标志的简称,如-v
,全称如--verbose
,以及其他信息,如参数类型和帮助文本。我们使用inventory::collect!
调用实例化一个插件注册表。
pub struct Flag {
short: char,
name: &'static str,
/* ... */
}
impl Flag {
pub const fn new(short: char, name: &'static str) -> Self {
Flag { short, name }
}
}
inventory::collect!(Flag);
这个collect!
调用必须在定义插件类型的同一包中进行。这个宏不会“运行”任何东西,所以将其放置在任何函数体之外。
注册插件
现在任何有权限访问Flag
类型的包都可以将标志作为插件进行注册。插件可以由声明插件类型的相同包注册,也可以由任何下游包注册。
inventory::submit! {
Flag::new('v', "verbose")
}
submit!
宏并不会“运行”任何东西,因此请将其放置在函数体之外。特别是要注意,所有源文件中所有 submit!
的调用都将同时生效。一个 submit!
调用不需要从 main
中调用才能执行。
遍历插件
值 inventory::iter::<T>
是一个迭代器,其元素类型为 &'static T
,它遍历所有注册的类型为 T
的插件。
for flag in inventory::iter::<Flag> {
println!("-{}, --{}", flag.short, flag.name);
}
无法保证迭代器遍历同一类型的插件时的顺序。它们可能以任何顺序被访问。
工作原理
库存是建立在类似于 C 中的 __attribute__((constructor))
的运行时初始化函数之上,类似于 ctor
包。每次对 inventory::submit!
的调用都会产生一个模拟器,该模拟器评估给定的表达式并将其注册到其对应类型的注册表中。这种注册作为静态链接元素的生命周期前的部分动态发生。动态加载库引入的元素在 dlopen 发生时注册。
平台支持包括 Linux、macOS、iOS、FreeBSD、Android、Windows 以及一些其他平台。除此之外,其他平台将发现没有任何插件被注册。
有关不涉及生命周期前的插件注册的另一种方法的更多信息,请参阅 linkme
包。
许可证
根据您的选择,许可受Apache License, Version 2.0 或 MIT license。除非您明确声明,否则根据 Apache-2.0 许可证定义的,您有意提交的任何贡献,都应以上述方式双许可,不附加任何其他条款或条件。
依赖项
~1.5MB
~36K SLoC