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.20")]
151#![no_std]
152#![deny(unsafe_op_in_unsafe_fn)]
153#![allow(
154 clippy::doc_markdown,
155 clippy::empty_enum,
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
164// Not public API.
165#[doc(hidden)]
166pub extern crate core;
167
168use core::cell::UnsafeCell;
169use core::marker::PhantomData;
170use core::ops::Deref;
171use core::ptr;
172#[cfg(target_family = "wasm")]
173use core::sync::atomic::AtomicBool;
174use core::sync::atomic::{AtomicPtr, Ordering};
175
176// Not public API. Used by generated code.
177#[doc(hidden)]
178pub struct Registry {
179 head: AtomicPtr<Node>,
180}
181
182// Not public API. Used by generated code.
183#[doc(hidden)]
184pub struct Node {
185 pub value: &'static dyn ErasedNode,
186 pub next: UnsafeCell<Option<&'static Node>>,
187 #[cfg(target_family = "wasm")]
188 pub initialized: AtomicBool,
189}
190
191// The `value` is Sync, and `next` is only mutated during submit, which is prior
192// to any reads.
193unsafe impl Sync for Node {}
194
195// Not public API. Used by generated code.
196#[doc(hidden)]
197pub trait ErasedNode: Sync {
198 // SAFETY: requires *node.value is of type Self.
199 unsafe fn submit(&self, node: &'static Node);
200}
201
202impl<T: Collect> ErasedNode for T {
203 unsafe fn submit(&self, node: &'static Node) {
204 unsafe {
205 T::registry().submit(new:node);
206 }
207 }
208}
209
210/// Trait bound corresponding to types that can be iterated by inventory::iter.
211///
212/// This trait cannot be implemented manually. Instead use the [`collect`] macro
213/// which expands to an implementation of this trait for the given type.
214///
215/// # Examples
216///
217/// ```
218/// use inventory::Collect;
219///
220/// fn count_plugins<T: Collect>() -> usize {
221/// inventory::iter::<T>.into_iter().count()
222/// }
223/// ```
224pub trait Collect: Sync + Sized + 'static {
225 #[doc(hidden)]
226 fn registry() -> &'static Registry;
227}
228
229impl Registry {
230 // Not public API. Used by generated code.
231 pub const fn new() -> Self {
232 Registry {
233 head: AtomicPtr::new(ptr::null_mut()),
234 }
235 }
236
237 // SAFETY: requires type of *new.value matches the $ty surrounding the
238 // declaration of this registry in inventory::collect macro.
239 unsafe fn submit(&'static self, new: &'static Node) {
240 // The WebAssembly linker uses an unreliable heuristic to determine
241 // whether a module is a "command-style" linkage, for which it will
242 // insert a call to `__wasm_call_ctors` at the top of every exported
243 // function. It expects that the embedder will call into such modules
244 // only once per instantiation. If this heuristic goes wrong, we can end
245 // up having our constructors invoked multiple times, which without this
246 // safeguard would lead to our registry's linked list becoming circular.
247 // On non-Wasm platforms, this check is unnecessary, so we skip it.
248 #[cfg(target_family = "wasm")]
249 if new.initialized.swap(true, Ordering::Relaxed) {
250 return;
251 }
252
253 let mut head = self.head.load(Ordering::Relaxed);
254 loop {
255 unsafe {
256 *new.next.get() = head.as_ref();
257 }
258 let new_ptr = new as *const Node as *mut Node;
259 match self
260 .head
261 .compare_exchange(head, new_ptr, Ordering::Release, Ordering::Relaxed)
262 {
263 Ok(_) => return,
264 Err(prev) => head = prev,
265 }
266 }
267 }
268}
269
270/// An iterator over plugins registered of a given type.
271///
272/// The value `inventory::iter::<T>` is an iterator with element type `&'static
273/// T`.
274///
275/// There is no guarantee about the order that plugins of the same type are
276/// visited by the iterator. They may be visited in any order.
277///
278/// # Examples
279///
280/// ```
281/// # struct Flag {
282/// # short: char,
283/// # name: &'static str,
284/// # }
285/// #
286/// # inventory::collect!(Flag);
287/// #
288/// # const IGNORE: &str = stringify! {
289/// use my_flags::Flag;
290/// # };
291///
292/// fn main() {
293/// for flag in inventory::iter::<Flag> {
294/// println!("-{}, --{}", flag.short, flag.name);
295/// }
296/// }
297/// ```
298///
299/// Refer to the [crate level documentation](index.html) for a complete example
300/// of instantiating a plugin registry and submitting plugins.
301#[allow(non_camel_case_types)]
302pub type iter<T> = private::iter<T>;
303
304mod void_iter {
305 enum Void {}
306
307 #[repr(C, packed)]
308 pub struct Iter<T>([*const T; 0], Void);
309
310 unsafe impl<T> Send for Iter<T> {}
311 unsafe impl<T> Sync for Iter<T> {}
312}
313
314mod value_iter {
315 #[doc(hidden)]
316 pub use crate::private::iter::iter;
317}
318
319mod private {
320 // Based on https://github.com/dtolnay/ghost
321 #[allow(non_camel_case_types)]
322 pub enum iter<T> {
323 __Phantom(crate::void_iter::Iter<T>),
324 iter,
325 }
326
327 #[doc(hidden)]
328 pub use crate::value_iter::*;
329}
330
331#[doc(hidden)]
332pub use crate::private::*;
333
334const _: () = {
335 fn into_iter<T: Collect>() -> Iter<T> {
336 let head = T::registry().head.load(Ordering::Acquire);
337 Iter {
338 // Head pointer is always null or valid &'static Node.
339 node: unsafe { head.as_ref() },
340 marker: PhantomData,
341 }
342 }
343
344 impl<T: Collect> IntoIterator for iter<T> {
345 type Item = &'static T;
346 type IntoIter = Iter<T>;
347
348 fn into_iter(self) -> Self::IntoIter {
349 into_iter()
350 }
351 }
352
353 #[doc(hidden)]
354 impl<T: Collect> Deref for iter<T> {
355 type Target = fn() -> Iter<T>;
356 fn deref(&self) -> &Self::Target {
357 &(into_iter as fn() -> Iter<T>)
358 }
359 }
360
361 pub struct Iter<T: 'static> {
362 node: Option<&'static Node>,
363 marker: PhantomData<T>,
364 }
365
366 impl<T: 'static> Iterator for Iter<T> {
367 type Item = &'static T;
368
369 fn next(&mut self) -> Option<Self::Item> {
370 let node = self.node?;
371 unsafe {
372 let value_ptr = (node.value as *const dyn ErasedNode).cast::<T>();
373 self.node = *node.next.get();
374 Some(&*value_ptr)
375 }
376 }
377 }
378
379 impl<T> Clone for Iter<T> {
380 fn clone(&self) -> Self {
381 Self {
382 node: self.node,
383 marker: PhantomData,
384 }
385 }
386 }
387};
388
389/// Associate a plugin registry with the specified type.
390///
391/// This call must be in the same crate that defines the plugin type. This macro
392/// does not "run" anything so place it outside of any function body.
393///
394/// # Examples
395///
396/// Suppose we are writing a command line flags library and want to allow any
397/// source file in the application to register command line flags that are
398/// relevant to it.
399///
400/// This is the flag registration style used by [gflags] and is better suited
401/// for large scale development than maintaining a single central list of flags,
402/// as the central list would become an endless source of merge conflicts.
403///
404/// [gflags]: https://gflags.github.io/gflags/
405///
406/// ```
407/// pub struct Flag {
408/// short: char,
409/// name: &'static str,
410/// /* ... */
411/// }
412///
413/// inventory::collect!(Flag);
414/// ```
415///
416/// Refer to the [crate level documentation](index.html) for a complete example
417/// of submitting plugins and iterating a plugin registry.
418#[macro_export]
419macro_rules! collect {
420 ($ty:ty) => {
421 impl $crate::Collect for $ty {
422 #[inline]
423 fn registry() -> &'static $crate::Registry {
424 static REGISTRY: $crate::Registry = $crate::Registry::new();
425 &REGISTRY
426 }
427 }
428 };
429}
430
431/// Enter an element into the plugin registry corresponding to its type.
432///
433/// This call may be in the same crate that defines the type, or downstream in
434/// any crate that depends on that crate.
435///
436/// This macro does not "run" anything so place it outside of any function body.
437/// In particular, note that all `submit!` invocations across all source files
438/// linked into your application all take effect simultaneously. A `submit!`
439/// invocation is not a statement that needs to be called from `main` in order
440/// to execute.
441///
442/// # Examples
443///
444/// Put `submit!` invocations outside of any function body.
445///
446/// ```
447/// # struct Flag;
448/// #
449/// # impl Flag {
450/// # const fn new(short: char, name: &'static str) -> Self {
451/// # Flag
452/// # }
453/// # }
454/// #
455/// # inventory::collect!(Flag);
456/// #
457/// inventory::submit! {
458/// Flag::new('v', "verbose")
459/// }
460/// #
461/// # fn main() {}
462/// ```
463///
464/// Do not try to invoke `submit!` from inside of a function body as it does not
465/// do what you want.
466///
467/// ```compile_fail
468/// // Do not do this.
469/// fn submit_flags(has_verbose_flag: bool) {
470/// if has_verbose_flag {
471/// inventory::submit! {
472/// Flag::new('v', "verbose")
473/// }
474/// }
475/// }
476/// ```
477///
478/// Refer to the [crate level documentation](index.html) for a complete example
479/// of instantiating and iterating a plugin registry.
480#[macro_export]
481macro_rules! submit {
482 ($($value:tt)*) => {
483 $crate::__do_submit! {
484 { $($value)* }
485 { $($value)* }
486 }
487 };
488}
489
490// Not public API.
491#[cfg(target_family = "wasm")]
492#[doc(hidden)]
493pub mod __private {
494 #[doc(hidden)]
495 pub use rustversion::attr;
496}
497
498// Not public API.
499#[doc(hidden)]
500#[macro_export]
501macro_rules! __do_submit {
502 (used={ $($used:tt)+ } $($value:tt)*) => {
503 #[allow(non_upper_case_globals)]
504 const _: () = {
505 static __INVENTORY: $crate::Node = $crate::Node {
506 value: &{ $($value)* },
507 next: $crate::core::cell::UnsafeCell::new($crate::core::option::Option::None),
508 #[cfg(target_family = "wasm")]
509 initialized: $crate::core::sync::atomic::AtomicBool::new(false),
510 };
511
512 #[cfg_attr(any(target_os = "linux", target_os = "android"), link_section = ".text.startup")]
513 unsafe extern "C" fn __ctor() {
514 unsafe { $crate::ErasedNode::submit(__INVENTORY.value, &__INVENTORY) }
515 }
516
517 // Linux/ELF: https://www.exploit-db.com/papers/13234
518 //
519 // macOS: https://blog.timac.org/2016/0716-constructor-and-destructor-attributes/
520 //
521 // Why .CRT$XCU on Windows? https://www.cnblogs.com/sunkang/archive/2011/05/24/2055635.html
522 // 'I'=C init, 'C'=C++ init, 'P'=Pre-terminators and 'T'=Terminators
523 $($used)+
524 #[cfg_attr(
525 all(
526 not(target_family = "wasm"),
527 any(
528 target_os = "linux",
529 target_os = "android",
530 target_os = "dragonfly",
531 target_os = "freebsd",
532 target_os = "haiku",
533 target_os = "illumos",
534 target_os = "netbsd",
535 target_os = "openbsd",
536 target_os = "none",
537 )
538 ),
539 link_section = ".init_array",
540 )]
541 #[cfg_attr(
542 target_family = "wasm",
543 $crate::__private::attr(
544 any(all(stable, since(1.85)), since(2024-12-18)),
545 link_section = ".init_array",
546 ),
547 )]
548 #[cfg_attr(
549 any(target_os = "macos", target_os = "ios"),
550 link_section = "__DATA,__mod_init_func",
551 )]
552 #[cfg_attr(windows, link_section = ".CRT$XCU")]
553 static __CTOR: unsafe extern "C" fn() = __ctor;
554 };
555 };
556
557 ({ #![used($($used:tt)+)] $($value:tt)* } { $pound:tt $bang:tt $brackets:tt $($dup:tt)* }) => {
558 $crate::__do_submit! {
559 used={ $pound $brackets }
560 $($value)*
561 }
562 };
563
564 ({ $($value:tt)* } { $($dup:tt)* }) => {
565 $crate::__do_submit! {
566 used={ #[used] }
567 $($value)*
568 }
569 };
570}
571