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 162 163 164
#![no_std] #![warn(missing_docs)] #![warn(rust_2018_idioms)] #![cfg_attr(doc, feature(doc_cfg))] #![cfg_attr(feature = "nightly", feature(cfg_target_has_atomic))] //! A set of process unique identifiers that can be used to //! identify values with minimal overhead within a single process //! //! see the [`Identifier`](crate::Identifier) trait for details //! //! ### features //! //! * `std` (default) - if you have the `std` feature on, it will supercede the `alloc` feature. //! This allows you to use: //! * `std` types to implement various traits, for example `Box<I>` will implemnt `Identifier` `I` //! * `thread_local` types (from the `*_tl`) //! * `make_global_reuse` (this requires internal locking using a `Mutex`) //! //! * `alloc` - this allows you to use without pulling in all of `std`: //! * `alloc` types to implement various traits, for example `Box<I>` will implemnt `Identifier` `I` //! //! * `nightly` - this allows you to use: //! * atomics on `no_std` targets that don't support 64-bit atomics #[cfg(feature = "std")] extern crate std; #[cfg(all(not(feature = "std"), feature = "alloc"))] extern crate alloc as std; #[doc(hidden)] pub mod macros; pub mod runtime; pub mod scoped; pub mod typeid; #[cfg(any(feature = "std", doc))] #[cfg_attr(doc, doc(cfg(feature = "std")))] pub mod typeid_tl; #[cfg(all(feature = "test", feature = "std"))] #[doc(hidden)] pub mod test_setup; pub use macros::Scalar; struct Invariant<T: ?Sized>(fn() -> *mut T); #[doc(hidden)] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct ThreadLocal(*mut ()); /// 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 cheap handle to the identifier, which you can use to mark other types /// as logically owned by the identifier. /// /// For example, this pattern is sound /// /// ```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() } /// } /// } /// ``` /// /// # Safety /// /// * `ident.owns(&handle)` must return true for any `handle` returned /// from `ident.handle()` regardless of when the handle was created. /// * If two handles compare equal, then `Identifier::owns` must act the /// same for both of them /// * i.e. it must return false for both handles, or it must return /// true for both handles /// * Two instances of `Identifier` must *never* return true for the same /// handle if they can both exist on the same thread. /// * In particular, it is unsound to implement `Identifier` on references pub unsafe trait Identifier: Eq { /// A handle which can be used to mark other types type Handle: Handle; /// Create a handle that this identifier owns fn handle(&self) -> Self::Handle; /// Check the current identifier owns the given handle fn owns(&self, handle: &Self::Handle) -> bool; } /// A handle to an [`Identifier`](Identifier). /// /// # Safety /// /// It is a safety bug for `Self` to be modified in such a way that its equality, /// as determined by the `Eq` trait, changes when compared using `PartialEq::Eq` /// or when cloned via `Clone::clone`. This is normally only possible through /// `Cell`, `RefCell`, global state, I/O, or unsafe code. pub unsafe trait Handle: Clone + Eq {} /// a type that has no safety (library) invariants pub trait Trivial: Copy { /// The canonical instance of `Self` const INSTANCE: Self; } #[cfg(any(feature = "std", feature = "alloc"))] unsafe impl<I: Identifier + ?Sized> Identifier for std::boxed::Box<I> { type Handle = I::Handle; #[inline] fn handle(&self) -> Self::Handle { I::handle(self) } #[inline] fn owns(&self, handle: &Self::Handle) -> bool { I::owns(self, handle) } }