Crate inventory

Source
Expand description

githubcrates-iodocs-rs


Typed distributed plugin registration.

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.

§Examples

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.

§Instantiating the plugin registry

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.

§Registering plugins

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.

§Iterating over plugins

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.

§WebAssembly and constructors

inventory supports all WebAssembly targets, including wasm*-unknown-unknown. However, in unusual circumstances, ensuring that constructors run may require some extra effort. The Wasm linker will synthesize a function extern "C" unsafe fn __wasm_call_ctors() which calls all constructors when invoked; this function will not be exported from the module unless you do so explicitly. Depending on the result of a heuristic, the linker may or may not insert a call to this function from the beginning of every function that your module exports. Specifically, it regards a module as having “command-style linkage” if:

  • it is not relocatable;
  • it is not a position-independent executable;
  • and it does not call __wasm_call_ctors, directly or indirectly, from any exported function.

The linker expects that the embedder will call into a command-style module only once per instantiation. Violation of this expectation can result in __wasm_call_ctors being called multiple times. This is dangerous in general, but safe and mostly harmless in the case of constructors generated by inventory, which are idempotent.

If you are building a module which relies on constructors and may be called into multiple times per instance, you should export __wasm_call_ctors (or a wrapper around it) and ensure that the embedder calls it immediately after instantiation. Even though inventory may work fine without this, it is still good practice, because it avoids unnecessary overhead from repeated constructor invocation. It also can prevent unsoundness if some of your constructors are generated by other crates or other programming languages.

#[cfg(target_family = "wasm")]
unsafe extern "C" {
    fn __wasm_call_ctors();
}

fn main() {
    #[cfg(target_family = "wasm")]
    unsafe {
        __wasm_call_ctors();
    }
}

Macros§

collect
Associate a plugin registry with the specified type.
submit
Enter an element into the plugin registry corresponding to its type.

Traits§

Collect
Trait bound corresponding to types that can be iterated by inventory::iter.

Type Aliases§

iter
An iterator over plugins registered of a given type.