This crate provides a way to set up a plugin registry into which plugins can be registered from any source file linked into your application. There does not need to be a central list of all the plugins.
[dependencies]
inventory = "0.3"Supports rustc 1.62+
Suppose we are writing a command line flags library and want to allow any source file in the application to register command line flags that are relevant to it.
This is the flag registration style used by gflags and is better suited for large scale development than maintaining a single central list of flags, as the central list would become an endless source of merge conflicts in an application developed simultaneously by thousands of developers.
Let's use a struct Flag as the plugin type, which will contain the short name
of the flag like -v, the full name like --verbose, and maybe other
information like argument type and help text. We instantiate a plugin registry
with an invocation of 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);This collect! call must be in the same crate that defines the plugin type.
This macro does not "run" anything so place it outside of any function body.
Now any crate with access to the Flag type can register flags as a plugin.
Plugins can be registered by the same crate that declares the plugin type, or by
any downstream crate.
inventory::submit! {
Flag::new('v', "verbose")
}The submit! macro does not "run" anything so place it outside of any function
body. In particular, note that all submit! invocations across all source files
linked into your application all take effect simultaneously. A submit!
invocation is not a statement that needs to be called from main in order to
execute.
The value inventory::iter::<T> is an iterator with element type &'static T
that iterates over all plugins registered of type T.
for flag in inventory::iter::<Flag> {
println!("-{}, --{}", flag.short, flag.name);
}There is no guarantee about the order that plugins of the same type are visited by the iterator. They may be visited in any order.
Inventory is built on runtime initialization functions similar to
__attribute__((constructor)) in C, and similar to the ctor crate. Each
call to inventory::submit! produces a shim that evaluates the given
expression and registers it into a registry of its corresponding type. This
registration happens dynamically as part of life-before-main for statically
linked elements. Elements brought in by a dynamically loaded library are
registered at the time that dlopen occurs.
Platform support includes Linux, macOS, iOS, FreeBSD, Android, Windows, WebAssembly, and a few others. Beyond this, other platforms will simply find that no plugins have been registered.
For a different approach to plugin registration that does not involve
life-before-main, see the linkme crate.
This crate requires Rust nightly when compiling for illumos targets due to its
dependency on the unstable used_with_arg feature.
To use this crate on illumos, you must enable the required feature in all
crates that use inventory. Add one of the following to the top of your crate's
entry point (typically main.rs or lib.rs):
For illumos-only applications:
#![feature(used_with_arg)]For cross-platform applications:
#[cfg_attr(target_os = "illumos", feature(used_with_arg))]The conditional approach allows your application to compile on stable Rust for other platforms while only requiring nightly on illumos.
This is because the illumos linker does not properly handle the multiple
.init_array sections created when using #[used]. You can find more
information here.
Licensed under either of Apache License, Version 2.0 or MIT license at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.