type_factory/lib.rs
1//! # `type_factory`
2//!
3//! Generates unique values of opaque types.
4//!
5//! ## How does it work?
6//!
7//! Using return-position `impl Trait` in traits ([RPITIT]), we can repeatedly
8//! create new opaque types out of previous ones.
9//!
10//! ```
11//! # use type_factory::Unique;
12//! let a = type_factory::try_init().unwrap();
13//! let (a, b) = a.split();
14//! let (b, c) = b.split();
15//! // `a`, `b`, and `c` are each of a distinct `impl Unique` type.
16//! ```
17//!
18//! Each <code>impl [Unique]</code> value is entirely unique and cannot be
19//! copied or cloned. Therefore, their primary use would be as brands.
20//!
21//! The [`toast-cell` crate][toast_cell] utilizes this property.
22//!
23//! [RPITIT]: https://github.com/rust-lang/rfcs/pull/3425
24//! [toast_cell]: https://crates.io/crates/toast-cell
25//!
26//! ## Minimum supported Rust version
27//!
28//! The MSRV is currently 1.75.
29//!
30//! This may change between minor versions.
31//!
32//! ## Similar crates
33//!
34//! - [`generativity`][generativity] provides a way to create unique invariant
35//! lifetimes, which may also be used as brands. However, it comes with a few
36//! drawbacks related to the method of creating these lifetimes.
37//! - [`unique-type`][unique_type] is nightly-only and uses unstable features to
38//! generate unique types in a similar fashion to this crate. However, it is
39//! intended to create *unconstructable* unique types that exist only on the
40//! type level, while this crate is for constructing unique types on the value
41//! level.
42//!
43//! [generativity]: https://crates.io/crates/generativity
44//! [unique_type]: https://crates.io/crates/unique-type
45
46// Attributes
47#![cfg_attr(not(any(doc, test)), no_std)]
48// Lints
49#![warn(missing_docs)]
50#![deny(clippy::multiple_unsafe_ops_per_block, unsafe_op_in_unsafe_fn)]
51
52#[cfg(any(doctest, test))]
53mod tests;
54
55mod private {
56 pub trait Sealed {}
57
58 pub struct Inner;
59
60 impl Sealed for Inner {}
61}
62use private::{Inner, Sealed};
63
64/// Implemented for unique types.
65///
66/// The initial `impl Unique` value may be procured by calling [`init`] or
67/// [`try_init`].
68#[must_use = "unique types do nothing unless used"]
69pub trait Unique: Sealed {
70 /// Generates more unique types.
71 ///
72 /// The original is consumed in order to ensure that the returned types are
73 /// globally unique.
74 fn split(self) -> (impl Unique, impl Unique);
75}
76
77impl Unique for Inner {
78 fn split(self) -> (impl Unique, impl Unique) {
79 (Inner, Inner)
80 }
81}
82
83/// Generates the initial unique type.
84///
85/// # Safety
86///
87/// This function should only be called once in order to guarantee that
88/// all generated types are globally unique.
89pub const unsafe fn init() -> impl Unique {
90 Inner
91}
92
93/// A safe, checked alternative to [`init`]. Returns `None` if the function was
94/// already called.
95///
96/// **Note**: Due to an implementation detail, this function is only available
97/// on platforms that support atomic operations on `u8`.
98#[cfg(target_has_atomic = "8")]
99pub fn try_init() -> Option<impl Unique> {
100 use core::sync::atomic::{AtomicBool, Ordering};
101
102 static ONCE: AtomicBool = AtomicBool::new(false);
103
104 if ONCE
105 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
106 .is_ok()
107 {
108 Some(Inner)
109 } else {
110 None
111 }
112}