pui_core/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![allow(clippy::declare_interior_mutable_const)]
3#![forbid(missing_docs, clippy::missing_safety_doc)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6//! `pui-core` provides process unique identifiers. These identifiers, as the name
7//! suggests are unique within the process they reside in. `pui-core` also provides
8//! thread-local unique identifiers that are unique within the thread they reside in.
9//!
10/// These identifiers can be used to enable safe (mostly) compile-time checked
11/// shared mutability.
12///
13/// ```rust
14/// use pui::Identifier;
15/// use std::cell::UnsafeCell;
16///
17/// struct Owner<I> {
18///     ident: I,
19/// }
20///
21/// struct Handle<H, T: ?Sized> {
22///     handle: H,
23///     value: UnsafeCell<T>,
24/// }
25///
26/// impl<H, T> Handle<H, T> {
27///     pub fn new(handle: H, value: T) -> Self {
28///         Self { handle, value: UnsafeCell::new(value) }
29///     }
30/// }
31///
32/// impl<I> Owner<I> {
33///     pub fn new(ident: I) -> Self {
34///         Self { ident }
35///     }
36/// }
37///
38/// impl<I: Identifier> Owner<I> {
39///     pub fn read<'a, T: ?Sized>(&'a self, handle: &'a Handle<I::Handle, T>) -> &'a T {
40///         assert!(self.ident.owns(&handle.handle));
41///         
42///         // This is safe because `ident` owns the `handle`, which means that `self`
43///         // is the only `Owner` that could shared access the underlying value
44///         // This is because:
45///         //  * the `Owner` owns the `Identifier`
46///         //  * when we read/write, we bind the lifetime of `self` and `Handle`
47///         //      to the lifetime of the output reference
48///         //  * we have shared access to `*self`
49///         
50///         unsafe { &*handle.value.get() }
51///     }
52///
53///     pub fn write<'a, T: ?Sized>(&'a mut self, handle: &'a Handle<I::Handle, T>) -> &'a mut T {
54///         assert!(self.ident.owns(&handle.handle));
55///         
56///         // This is safe because `ident` owns the `handle`, which means that `self`
57///         // is the only `Owner` that could exclusive access the underlying value
58///         // This is because:
59///         //  * the `Owner` owns the `Identifier`
60///         //  * when we read/write, we bind the lifetime of `self` and `Handle`
61///         //      to the lifetime of the output reference
62///         //  * we have exclusive access to `*self`
63///         
64///         unsafe { &mut *handle.value.get() }
65///     }
66/// }
67/// ```
68///
69
70#[cfg(all(not(feature = "std"), feature = "alloc",))]
71extern crate alloc as std;
72
73#[doc(hidden)]
74pub mod export;
75pub mod pool;
76pub mod scalar;
77
78pub mod dynamic;
79pub mod scoped;
80
81pub(crate) use seal::Seal;
82#[forbid(missing_docs)]
83mod seal {
84    pub trait Seal {}
85}
86
87/// A const initializer
88pub trait Init {
89    /// The initial value of `Self`
90    const INIT: Self;
91}
92
93/// A type that an [`Identifier`] produces and is owned by an `Identifier`
94///
95/// If two tokens compare equal, then they should behave identically under
96/// `Identifier::owns_token` operation.
97///
98/// # Safety
99///
100/// * it should be not possible to change the behavior of `PartialEq::eq`
101///   or `Identifier::owns_token` via a shared reference to a `Token`
102/// * clones/copies of a token should be equal to each other
103pub unsafe trait Token: Clone + Eq {}
104/// A [`Token`] that has no safety requirements
105pub trait Trivial: Token + Init {}
106
107/// An [`Identifier`] who's tokens are guaranteed to *never* be owned by another
108/// `Identifier`, even if this one is dropped
109pub unsafe trait OneShotIdentifier: Identifier {}
110
111/// An [`Identifier`] is a process unique identifier
112///
113/// you are guaranteed that two instances of this identifier will *never* compare equal
114/// You can also get a token that this identifier recognizes, which you can use to mark
115/// other types as logically owned by the identifier. No other identifier will recognize
116/// tokens made be a different identifier while both identifiers are live.
117///
118/// # Safety
119///
120/// * `ident.owns(&token)` must return true for any `token` returned
121///     from `ident.token()` regardless of when the token was created.
122/// * If two tokens compare equal, then `Identifier::owns` must act the
123///     same for both of them
124///     * i.e. it must return false for both tokens, or it must return
125///         true for both tokens
126/// * Two instances of `Identifier` must *never* return true for the same
127///     token if either the two identifier or the tokens they generate can
128///     both exist on the same thread.
129pub unsafe trait Identifier {
130    /// The tokens that this `Identifier` generates
131    type Token: Token;
132
133    #[inline]
134    /// Check if this token was created by this identifier
135    fn owns_token(&self, token: &Self::Token) -> bool { self.token() == *token }
136
137    /// Create a new token
138    fn token(&self) -> Self::Token;
139}
140
141unsafe impl<I: ?Sized + Identifier> Identifier for &mut I {
142    type Token = I::Token;
143
144    fn owns_token(&self, token: &Self::Token) -> bool { I::owns_token(self, token) }
145
146    fn token(&self) -> Self::Token { I::token(self) }
147}
148
149#[cfg(feature = "alloc")]
150#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
151unsafe impl<I: ?Sized + Identifier> Identifier for std::boxed::Box<I> {
152    type Token = I::Token;
153
154    fn owns_token(&self, token: &Self::Token) -> bool { I::owns_token(self, token) }
155
156    fn token(&self) -> Self::Token { I::token(self) }
157}
158
159#[cfg(feature = "alloc")]
160#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
161unsafe impl<I: ?Sized + OneShotIdentifier> OneShotIdentifier for std::boxed::Box<I> {}