inventory/
lib.rs

1//! [![github]](https://github.com/dtolnay/inventory) [![crates-io]](https://crates.io/crates/inventory) [![docs-rs]](https://docs.rs/inventory)
2//!
3//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
4//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
5//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
6//!
7//! <br>
8//!
9//! **Typed distributed plugin registration.**
10//!
11//! This crate provides a way to set up a plugin registry into which plugins
12//! can be registered from any source file linked into your application. There
13//! does not need to be a central list of all the plugins.
14//!
15//! # Examples
16//!
17//! Suppose we are writing a command line flags library and want to allow any
18//! source file in the application to register command line flags that are
19//! relevant to it.
20//!
21//! This is the flag registration style used by [gflags] and is better suited
22//! for large scale development than maintaining a single central list of flags,
23//! as the central list would become an endless source of merge conflicts in an
24//! application developed simultaneously by thousands of developers.
25//!
26//! [gflags]: https://gflags.github.io/gflags/
27//!
28//! ## Instantiating the plugin registry
29//!
30//! Let's use a `struct Flag` as the plugin type, which will contain the short
31//! name of the flag like `-v`, the full name like `--verbose`, and maybe other
32//! information like argument type and help text. We instantiate a plugin
33//! registry with an invocation of `inventory::collect!`.
34//!
35//! ```
36//! pub struct Flag {
37//!     short: char,
38//!     name: &'static str,
39//!     /* ... */
40//! }
41//!
42//! impl Flag {
43//!     pub const fn new(short: char, name: &'static str) -> Self {
44//!         Flag { short, name }
45//!     }
46//! }
47//!
48//! inventory::collect!(Flag);
49//! ```
50//!
51//! This `collect!` call must be in the same crate that defines the plugin type.
52//! This macro does not "run" anything so place it outside of any function body.
53//!
54//! ## Registering plugins
55//!
56//! Now any crate with access to the `Flag` type can register flags as a plugin.
57//! Plugins can be registered by the same crate that declares the plugin type,
58//! or by any downstream crate.
59//!
60//! ```
61//! # struct Flag;
62//! #
63//! # impl Flag {
64//! #     const fn new(short: char, name: &'static str) -> Self {
65//! #         Flag
66//! #     }
67//! # }
68//! #
69//! # inventory::collect!(Flag);
70//! #
71//! inventory::submit! {
72//!     Flag::new('v', "verbose")
73//! }
74//! #
75//! # fn main() {}
76//! ```
77//!
78//! The `submit!` macro does not "run" anything so place it outside of any
79//! function body. In particular, note that all `submit!` invocations across all
80//! source files linked into your application all take effect simultaneously. A
81//! `submit!` invocation is not a statement that needs to be called from `main`
82//! in order to execute.
83//!
84//! ## Iterating over plugins
85//!
86//! The value `inventory::iter::<T>` is an iterator with element type `&'static
87//! T` that iterates over all plugins registered of type `T`.
88//!
89//! ```
90//! # struct Flag {
91//! #     short: char,
92//! #     name: &'static str,
93//! # }
94//! #
95//! # inventory::collect!(Flag);
96//! #
97//! for flag in inventory::iter::<Flag> {
98//!     println!("-{}, --{}", flag.short, flag.name);
99//! }
100//! ```
101//!
102//! There is no guarantee about the order that plugins of the same type are
103//! visited by the iterator. They may be visited in any order.
104//!
105//! ## WebAssembly and constructors
106//!
107//! `inventory` supports all WebAssembly targets, including
108//! `wasm*-unknown-unknown`. However, in unusual circumstances, ensuring that
109//! constructors run may require some extra effort. The Wasm linker will
110//! synthesize a function `extern "C" unsafe fn __wasm_call_ctors()` which calls
111//! all constructors when invoked; this function will *not* be exported from the
112//! module unless you do so explicitly. Depending on the result of a heuristic,
113//! the linker may or may not insert a call to this function from the beginning
114//! of every function that your module exports. Specifically, it regards a
115//! module as having "command-style linkage" if:
116//!
117//! * it is not relocatable;
118//! * it is not a position-independent executable;
119//! * and it does not call `__wasm_call_ctors`, directly or indirectly, from any
120//!   exported function.
121//!
122//! The linker expects that the embedder will call into a command-style module
123//! only once per instantiation. Violation of this expectation can result in
124//! `__wasm_call_ctors` being called multiple times. This is dangerous in
125//! general, but safe and mostly harmless in the case of constructors generated
126//! by `inventory`, which are idempotent.
127//!
128//! If you are building a module which relies on constructors and may be called
129//! into multiple times per instance, you should export `__wasm_call_ctors` (or
130//! a wrapper around it) and ensure that the embedder calls it immediately after
131//! instantiation. Even though `inventory` may work fine without this, it is
132//! still good practice, because it avoids unnecessary overhead from repeated
133//! constructor invocation. It also can prevent unsoundness if some of your
134//! constructors are generated by other crates or other programming languages.
135//!
136//! ```
137//! #[cfg(target_family = "wasm")]
138//! unsafe extern "C" {
139//!     fn __wasm_call_ctors();
140//! }
141//!
142//! fn main() {
143//!     #[cfg(target_family = "wasm")]
144//!     unsafe {
145//!         __wasm_call_ctors();
146//!     }
147//! }
148//! ```
149
150#![doc(html_root_url = "https://docs.rs/inventory/0.3.24")]
151#![no_std]
152#![deny(unsafe_op_in_unsafe_fn)]
153#![allow(
154    clippy::doc_markdown,
155    clippy::empty_enums,
156    clippy::expl_impl_clone_on_copy,
157    clippy::let_underscore_untyped,
158    clippy::let_unit_value,
159    clippy::must_use_candidate,
160    clippy::new_without_default,
161    clippy::semicolon_if_nothing_returned, // https://github.com/rust-lang/rust-clippy/issues/7324
162)]
163
164use core::cell::UnsafeCell;
165use core::marker::PhantomData;
166use core::ops::Deref;
167use core::ptr;
168#[cfg(target_family = "wasm")]
169use core::sync::atomic::AtomicBool;
170use core::sync::atomic::{AtomicPtr, Ordering};
171
172// Not public API. Used by generated code.
173#[doc(hidden)]
174pub struct Registry {
175    head: AtomicPtr<Node>,
176}
177
178// Not public API. Used by generated code.
179#[doc(hidden)]
180pub struct Node {
181    pub value: &'static dyn ErasedNode,
182    pub next: UnsafeCell<Option<&'static Node>>,
183    #[cfg(target_family = "wasm")]
184    pub initialized: AtomicBool,
185}
186
187// The `value` is Sync, and `next` is only mutated during submit, which is prior
188// to any reads.
189unsafe impl Sync for Node {}
190
191// Not public API. Used by generated code.
192#[doc(hidden)]
193pub trait ErasedNode: Sync {
194    // SAFETY: requires *node.value is of type Self.
195    unsafe fn submit(&self, node: &'static Node);
196}
197
198impl<T: Collect> ErasedNode for T {
199    unsafe fn submit(&self, node: &'static Node) {
200        unsafe {
201            T::registry().submit(node);
202        }
203    }
204}
205
206/// Trait bound corresponding to types that can be iterated by inventory::iter.
207///
208/// This trait cannot be implemented manually. Instead use the [`collect`] macro
209/// which expands to an implementation of this trait for the given type.
210///
211/// # Examples
212///
213/// ```
214/// use inventory::Collect;
215///
216/// fn count_plugins<T: Collect>() -> usize {
217///     inventory::iter::<T>.into_iter().count()
218/// }
219/// ```
220pub trait Collect: Sync + Sized + 'static {
221    #[doc(hidden)]
222    fn registry() -> &'static Registry;
223}
224
225impl Registry {
226    // Not public API. Used by generated code.
227    pub const fn new() -> Self {
228        Registry {
229            head: AtomicPtr::new(ptr::null_mut()),
230        }
231    }
232
233    // SAFETY: requires type of *new.value matches the $ty surrounding the
234    // declaration of this registry in inventory::collect macro.
235    unsafe fn submit(&'static self, new: &'static Node) {
236        // The WebAssembly linker uses an unreliable heuristic to determine
237        // whether a module is a "command-style" linkage, for which it will
238        // insert a call to  `__wasm_call_ctors` at the top of every exported
239        // function. It expects that the embedder will call into such modules
240        // only once per instantiation. If this heuristic goes wrong, we can end
241        // up having our constructors invoked multiple times, which without this
242        // safeguard would lead to our registry's linked list becoming circular.
243        // On non-Wasm platforms, this check is unnecessary, so we skip it.
244        #[cfg(target_family = "wasm")]
245        if new.initialized.swap(true, Ordering::Relaxed) {
246            return;
247        }
248
249        let mut head = self.head.load(Ordering::Relaxed);
250        loop {
251            unsafe {
252                *new.next.get() = head.as_ref();
253            }
254            let new_ptr = ptr::addr_of!(*new).cast_mut();
255            match self
256                .head
257                .compare_exchange(head, new_ptr, Ordering::Release, Ordering::Relaxed)
258            {
259                Ok(_) => return,
260                Err(prev) => head = prev,
261            }
262        }
263    }
264}
265
266/// An iterator over plugins registered of a given type.
267///
268/// The value `inventory::iter::<T>` is an iterator with element type `&'static
269/// T`.
270///
271/// There is no guarantee about the order that plugins of the same type are
272/// visited by the iterator. They may be visited in any order.
273///
274/// # Examples
275///
276/// ```
277/// # struct Flag {
278/// #     short: char,
279/// #     name: &'static str,
280/// # }
281/// #
282/// # inventory::collect!(Flag);
283/// #
284/// # const IGNORE: &str = stringify! {
285/// use my_flags::Flag;
286/// # };
287///
288/// fn main() {
289///     for flag in inventory::iter::<Flag> {
290///         println!("-{}, --{}", flag.short, flag.name);
291///     }
292/// }
293/// ```
294///
295/// Refer to the [crate level documentation](index.html) for a complete example
296/// of instantiating a plugin registry and submitting plugins.
297#[allow(non_camel_case_types)]
298pub type iter<T> = private::iter<T>;
299
300mod void_iter {
301    enum Void {}
302
303    #[repr(C, packed)]
304    pub struct Iter<T>([*const T; 0], Void);
305
306    unsafe impl<T> Send for Iter<T> {}
307    unsafe impl<T> Sync for Iter<T> {}
308}
309
310mod value_iter {
311    #[doc(hidden)]
312    pub use crate::private::iter::iter;
313}
314
315mod private {
316    // Based on https://github.com/dtolnay/ghost
317    #[allow(non_camel_case_types)]
318    pub enum iter<T> {
319        __Phantom(crate::void_iter::Iter<T>),
320        iter,
321    }
322
323    #[doc(hidden)]
324    pub use crate::value_iter::*;
325}
326
327#[doc(hidden)]
328pub use crate::private::*;
329
330const _: () = {
331    fn into_iter<T: Collect>() -> Iter<T> {
332        let head = T::registry().head.load(Ordering::Acquire);
333        Iter {
334            // Head pointer is always null or valid &'static Node.
335            node: unsafe { head.as_ref() },
336            marker: PhantomData,
337        }
338    }
339
340    impl<T: Collect> IntoIterator for iter<T> {
341        type Item = &'static T;
342        type IntoIter = Iter<T>;
343
344        fn into_iter(self) -> Self::IntoIter {
345            into_iter()
346        }
347    }
348
349    #[doc(hidden)]
350    impl<T: Collect> Deref for iter<T> {
351        type Target = fn() -> Iter<T>;
352        fn deref(&self) -> &Self::Target {
353            &(into_iter as fn() -> Iter<T>)
354        }
355    }
356
357    pub struct Iter<T: 'static> {
358        node: Option<&'static Node>,
359        marker: PhantomData<T>,
360    }
361
362    impl<T: 'static> Iterator for Iter<T> {
363        type Item = &'static T;
364
365        fn next(&mut self) -> Option<Self::Item> {
366            let node = self.node?;
367            unsafe {
368                let value_ptr = ptr::addr_of!(*node.value).cast::<T>();
369                self.node = *node.next.get();
370                Some(&*value_ptr)
371            }
372        }
373    }
374
375    impl<T> Clone for Iter<T> {
376        fn clone(&self) -> Self {
377            Self {
378                node: self.node,
379                marker: PhantomData,
380            }
381        }
382    }
383};
384
385/// Associate a plugin registry with the specified type.
386///
387/// This call must be in the same crate that defines the plugin type. This macro
388/// does not "run" anything so place it outside of any function body.
389///
390/// # Examples
391///
392/// Suppose we are writing a command line flags library and want to allow any
393/// source file in the application to register command line flags that are
394/// relevant to it.
395///
396/// This is the flag registration style used by [gflags] and is better suited
397/// for large scale development than maintaining a single central list of flags,
398/// as the central list would become an endless source of merge conflicts.
399///
400/// [gflags]: https://gflags.github.io/gflags/
401///
402/// ```
403/// pub struct Flag {
404///     short: char,
405///     name: &'static str,
406///     /* ... */
407/// }
408///
409/// inventory::collect!(Flag);
410/// ```
411///
412/// Refer to the [crate level documentation](index.html) for a complete example
413/// of submitting plugins and iterating a plugin registry.
414#[macro_export]
415macro_rules! collect {
416    ($ty:ty) => {
417        impl $crate::Collect for $ty {
418            #[inline]
419            fn registry() -> &'static $crate::Registry {
420                static REGISTRY: $crate::Registry = $crate::Registry::new();
421                &REGISTRY
422            }
423        }
424    };
425}
426
427/// Enter an element into the plugin registry corresponding to its type.
428///
429/// This call may be in the same crate that defines the type, or downstream in
430/// any crate that depends on that crate.
431///
432/// This macro does not "run" anything so place it outside of any function body.
433/// In particular, note that all `submit!` invocations across all source files
434/// linked into your application all take effect simultaneously. A `submit!`
435/// invocation is not a statement that needs to be called from `main` in order
436/// to execute.
437///
438/// # Examples
439///
440/// Put `submit!` invocations outside of any function body.
441///
442/// ```
443/// # struct Flag;
444/// #
445/// # impl Flag {
446/// #     const fn new(short: char, name: &'static str) -> Self {
447/// #         Flag
448/// #     }
449/// # }
450/// #
451/// # inventory::collect!(Flag);
452/// #
453/// inventory::submit! {
454///     Flag::new('v', "verbose")
455/// }
456/// #
457/// # fn main() {}
458/// ```
459///
460/// Do not try to invoke `submit!` from inside of a function body as it does not
461/// do what you want.
462///
463/// ```compile_fail
464/// // Do not do this.
465/// fn submit_flags(has_verbose_flag: bool) {
466///     if has_verbose_flag {
467///         inventory::submit! {
468///             Flag::new('v', "verbose")
469///         }
470///     }
471/// }
472/// ```
473///
474/// Refer to the [crate level documentation](index.html) for a complete example
475/// of instantiating and iterating a plugin registry.
476#[macro_export]
477macro_rules! submit {
478    ($($value:tt)*) => {
479        $crate::__do_submit! {
480            { $($value)* }
481            { $($value)* }
482        }
483    };
484}
485
486// Not public API.
487#[doc(hidden)]
488pub mod __private {
489    #[doc(hidden)]
490    pub use core::option::Option;
491
492    #[cfg(target_family = "wasm")]
493    #[doc(hidden)]
494    pub use rustversion::attr;
495
496    // Type alias to sidestep clippy::disallowed_types in downstream projects
497    // that use Loom.
498    #[doc(hidden)]
499    pub type UnsafeCell<T> = core::cell::UnsafeCell<T>;
500
501    // Type alias to sidestep clippy::disallowed_types in downstream projects
502    // that use Loom.
503    #[cfg(target_family = "wasm")]
504    #[doc(hidden)]
505    pub type AtomicBool = core::sync::atomic::AtomicBool;
506}
507
508// Not public API.
509#[doc(hidden)]
510#[macro_export]
511macro_rules! __do_submit {
512    (used={ $($used:tt)+ } $($value:tt)*) => {
513        #[allow(non_upper_case_globals)]
514        const _: () = {
515            static __INVENTORY: $crate::Node = $crate::Node {
516                value: &{ $($value)* },
517                next: $crate::__private::UnsafeCell::new($crate::__private::Option::None),
518                #[cfg(target_family = "wasm")]
519                initialized: $crate::__private::AtomicBool::new(false),
520            };
521
522            #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")]
523            unsafe extern "C" fn __ctor() {
524                unsafe { $crate::ErasedNode::submit(__INVENTORY.value, &__INVENTORY) }
525            }
526
527            // Linux/ELF: https://www.exploit-db.com/papers/13234
528            //
529            // macOS: https://blog.timac.org/2016/0716-constructor-and-destructor-attributes/
530            //
531            // Why .CRT$XCU on Windows? https://www.cnblogs.com/sunkang/archive/2011/05/24/2055635.html
532            // 'I'=C init, 'C'=C++ init, 'P'=Pre-terminators and 'T'=Terminators
533            $($used)+
534            #[cfg_attr(
535                all(
536                    not(target_family = "wasm"),
537                    any(
538                        target_os = "linux",
539                        target_os = "android",
540                        target_os = "dragonfly",
541                        target_os = "freebsd",
542                        target_os = "haiku",
543                        target_os = "illumos",
544                        target_os = "netbsd",
545                        target_os = "nto",
546                        target_os = "openbsd",
547                        target_os = "vxworks",
548                        target_os = "none",
549                    )
550                ),
551                link_section = ".init_array",
552            )]
553            #[cfg_attr(
554                target_family = "wasm",
555                $crate::__private::attr(
556                    any(all(stable, since(1.85)), since(2024-12-18)),
557                    link_section = ".init_array",
558                ),
559            )]
560            #[cfg_attr(
561                any(target_os = "macos", target_os = "ios"),
562                link_section = "__DATA,__mod_init_func,mod_init_funcs",
563            )]
564            #[cfg_attr(windows, link_section = ".CRT$XCU")]
565            static __CTOR: unsafe extern "C" fn() = __ctor;
566        };
567    };
568
569    ({ #![used($($used:tt)+)] $($value:tt)* } { $pound:tt $bang:tt $brackets:tt $($dup:tt)* }) => {
570        $crate::__do_submit! {
571            used={ $pound $brackets }
572            $($value)*
573        }
574    };
575
576    ({ $($value:tt)* } { $($dup:tt)* }) => {
577        $crate::__do_submit! {
578            used={ #[used] }
579            $($value)*
580        }
581    };
582}