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> {}