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