| 1 | #![cfg_attr (not(test), no_std)] |
| 2 | |
| 3 | //! Create a trusted carrier with a new lifetime that is guaranteed to be |
| 4 | //! unique among other trusted carriers. When you call [`make_guard!`] to make a |
| 5 | //! unique lifetime, the macro creates a [`Guard`] to hold it. This guard can be |
| 6 | //! converted `into` an [`Id`], which can be stored in structures to uniquely |
| 7 | //! "brand" them. A different invocation of the macro will produce a new |
| 8 | //! lifetime that cannot be unified. The only way to construct these types is |
| 9 | //! with [`make_guard!`] or `unsafe` code. |
| 10 | //! |
| 11 | //! ```rust |
| 12 | //! use generativity::{Id, make_guard}; |
| 13 | //! struct Struct<'id>(Id<'id>); |
| 14 | //! make_guard!(a); |
| 15 | //! Struct(a.into()); |
| 16 | //! ``` |
| 17 | //! |
| 18 | //! This is the concept of "generative" lifetime brands. `Guard` and `Id` are |
| 19 | //! [invariant](https://doc.rust-lang.org/nomicon/subtyping.html#variance) over |
| 20 | //! their lifetime parameter, meaning that it is never valid to substitute or |
| 21 | //! otherwise coerce `Id<'a>` into `Id<'b>`, for *any* concrete `'a` or `'b`, |
| 22 | //! *including* the `'static` lifetime. |
| 23 | //! |
| 24 | //! Any invariant lifetime can be "trusted" to carry a brand, so long as they |
| 25 | //! are known to be restricted to carrying a brand, and haven't been derived |
| 26 | //! from some untrusted lifetime (or are completely unbound). When using this |
| 27 | //! library, it is recommended to always use `Id<'id>` to carry the brand, as |
| 28 | //! this reduces the risk of accidentally trusting an untrusted lifetime. |
| 29 | //! Importantly, non-invariant lifetimes *cannot* be trusted, as the variance |
| 30 | //! allows lifetimes to be contracted to match and copy the brand lifetime. |
| 31 | //! |
| 32 | //! To achieve lifetime invariance without `Id`, there are two standard ways: |
| 33 | //! `PhantomData<&'a mut &'a ()>` and `PhantomData<fn(&'a ()) -> &'a ()>`. The |
| 34 | //! former works because `&mut T` is invariant over `T`, and the latter works |
| 35 | //! because `fn(T)` is *contra*variant over `T` and `fn() -> T` is *co*variant |
| 36 | //! over `T`, which combines to *in*variance. Both are equivalent in this case |
| 37 | //! with `T = ()`, but `fn(T) -> T` is generally preferred if the only purpose |
| 38 | //! is to indicate invariance, as function pointers are a perfect cover for all |
| 39 | //! auto traits (e.g. `Send`, `Sync`, `Unpin`, `UnwindSafe`, etc.) and thus |
| 40 | //! only indicates invariance, whereas `&mut T` can carry further implication |
| 41 | //! of "by example" use of `PhantomData`. |
| 42 | |
| 43 | use core_::fmt; |
| 44 | use core_::marker::PhantomData; |
| 45 | |
| 46 | #[doc (hidden)] |
| 47 | /// NOT STABLE PUBLIC API. Previously Used by the expansion of [`make_guard!`]. |
| 48 | pub extern crate core as core_; |
| 49 | |
| 50 | /// A phantomdata-like type taking a single invariant lifetime. |
| 51 | /// |
| 52 | /// Used to manipulate and store the unique invariant lifetime obtained from |
| 53 | /// [`Guard`]. Use `guard.into()` to create a new `Id`. |
| 54 | /// |
| 55 | /// Holding `Id<'id>` indicates that the lifetime `'id` is a trusted brand. |
| 56 | /// `'id` will not unify with another trusted brand lifetime unless it comes |
| 57 | /// from the same original brand (i.e. the same invocation of [`make_guard!`]). |
| 58 | #[repr (transparent)] |
| 59 | #[derive (Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] |
| 60 | pub struct Id<'id> { |
| 61 | phantom: PhantomData<fn(&'id ()) -> &'id ()>, |
| 62 | } |
| 63 | |
| 64 | impl<'id> Id<'id> { |
| 65 | /// Construct an `Id` with an unbounded lifetime. |
| 66 | /// |
| 67 | /// You should not need to use this function; use [`make_guard!`] instead. |
| 68 | /// |
| 69 | /// # Safety |
| 70 | /// |
| 71 | /// `Id` holds an invariant lifetime that must be derived from a generative |
| 72 | /// brand. Using this function directly is the "I know what I'm doing" |
| 73 | /// button; restrict the lifetime to a known brand immediately to avoid |
| 74 | /// introducing potential unsoundness. |
| 75 | pub unsafe fn new() -> Self { |
| 76 | Id { |
| 77 | phantom: PhantomData, |
| 78 | } |
| 79 | } |
| 80 | } |
| 81 | |
| 82 | impl<'id> fmt::Debug for Id<'id> { |
| 83 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 84 | f.debug_struct(name:"#[invariant] 'id" ).finish() |
| 85 | } |
| 86 | } |
| 87 | |
| 88 | impl<'id> From<Guard<'id>> for Id<'id> { |
| 89 | fn from(guard: Guard<'id>) -> Self { |
| 90 | guard.id |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | /// An invariant lifetime phantomdata-alike that is guaranteed to be unique |
| 95 | /// with respect to other trusted invariant lifetimes. |
| 96 | /// |
| 97 | /// In effect, this means that `'id` is a "generative brand". Use [`make_guard`] |
| 98 | /// to obtain a new `Guard`. |
| 99 | #[repr (transparent)] |
| 100 | #[derive (Eq, PartialEq)] |
| 101 | pub struct Guard<'id> { |
| 102 | #[allow (unused)] |
| 103 | id: Id<'id>, |
| 104 | } |
| 105 | |
| 106 | impl<'id> Guard<'id> { |
| 107 | /// Construct a `Guard` with an unbound lifetime. |
| 108 | /// |
| 109 | /// You should not need to use this function; use [`make_guard!`] instead. |
| 110 | /// |
| 111 | /// # Safety |
| 112 | /// |
| 113 | /// `Guard` holds an invariant lifetime that must be an unused generative |
| 114 | /// brand. Using this function directly is the "I know what I'm doing" |
| 115 | /// button; restrict the lifetime to a known brand immediately to avoid |
| 116 | /// introducing potential unsoundness. |
| 117 | pub unsafe fn new(id: Id<'id>) -> Guard<'id> { |
| 118 | Guard { id } |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | impl<'id> fmt::Debug for Guard<'id> { |
| 123 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| 124 | f.debug_struct(name:"#[unique] 'id" ).finish() |
| 125 | } |
| 126 | } |
| 127 | |
| 128 | #[doc (hidden)] |
| 129 | /// NOT STABLE PUBLIC API. Used by the expansion of [`make_guard!`]. |
| 130 | pub struct LifetimeBrand<'id> { |
| 131 | phantom: PhantomData<&'id Id<'id>>, |
| 132 | } |
| 133 | |
| 134 | impl<'id> Drop for LifetimeBrand<'id> { |
| 135 | #[inline (always)] |
| 136 | fn drop(&mut self) { |
| 137 | // This impl purposefully left blank. The presence of a Drop impl gives |
| 138 | // the `make_guard` type drop glue, dropping it at the end of scope. |
| 139 | // Importantly, this ensures that the compiler has to consider `'id` |
| 140 | // live at the point that this type is dropped, because this impl could |
| 141 | // potentially use data borrowed that lifetime. #[inline(always)] just |
| 142 | // serves to make it easier to optimize out the noop function call. |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | #[doc (hidden)] |
| 147 | /// NOT STABLE PUBLIC API. Used by the expansion of [`make_guard!`]. |
| 148 | impl<'id> LifetimeBrand<'id> { |
| 149 | #[doc (hidden)] |
| 150 | #[inline (always)] |
| 151 | /// NOT STABLE PUBLIC API. Used by the expansion of [`make_guard!`]. |
| 152 | pub unsafe fn new(_: &'id Id<'id>) -> LifetimeBrand<'id> { |
| 153 | // This function serves to entangle the `'id` lifetime, making it into |
| 154 | // a proper lifetime brand. The `'id` region may open at any point, but |
| 155 | // it must end in-between the drop timing of this `LifetimeBrand` and |
| 156 | // the `Id` binding used to create it. |
| 157 | LifetimeBrand { |
| 158 | phantom: PhantomData, |
| 159 | } |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | /// Create a `Guard` with a unique invariant lifetime (with respect to other |
| 164 | /// trusted/invariant lifetime brands). |
| 165 | /// |
| 166 | /// Multiple `make_guard` lifetimes will always fail to unify: |
| 167 | /// |
| 168 | /// ```rust,compile_fail,E0597 |
| 169 | /// # // trybuild ui test tests/ui/crossed_streams.rs |
| 170 | /// # use generativity::make_guard; |
| 171 | /// make_guard!(a); |
| 172 | /// make_guard!(b); |
| 173 | /// dbg!(a == b); // ERROR (here == is a static check) |
| 174 | /// ``` |
| 175 | #[macro_export ] |
| 176 | macro_rules! make_guard { |
| 177 | ($name:ident) => { |
| 178 | // SAFETY: The lifetime given to `$name` is unique among trusted brands. |
| 179 | // We know this because of how we carefully control drop timing here. |
| 180 | // The branded lifetime's end is bound to be no later than when the |
| 181 | // `branded_place` is invalidated at the end of scope, but also must be |
| 182 | // no sooner than `lifetime_brand` is dropped, also at the end of scope. |
| 183 | // Some other variant lifetime could be constrained to be equal to the |
| 184 | // brand lifetime, but no other lifetime branded by `make_guard!` can, |
| 185 | // as its brand lifetime has a distinct drop time from this one. QED |
| 186 | let branded_place = unsafe { $crate::Id::new() }; |
| 187 | #[allow(unused)] |
| 188 | let lifetime_brand = unsafe { $crate::LifetimeBrand::new(&branded_place) }; |
| 189 | let $name = unsafe { $crate::Guard::new(branded_place) }; |
| 190 | }; |
| 191 | } |
| 192 | |
| 193 | #[cfg (test)] |
| 194 | mod test { |
| 195 | use super::*; |
| 196 | use std::panic::{RefUnwindSafe, UnwindSafe}; |
| 197 | |
| 198 | #[test ] |
| 199 | fn dont_error_in_general() { |
| 200 | make_guard!(a); |
| 201 | make_guard!(b); |
| 202 | assert_eq!(a, a); |
| 203 | assert_eq!(b, b); |
| 204 | } |
| 205 | |
| 206 | #[test ] |
| 207 | fn test_oibits() { |
| 208 | fn assert_oibits<T>(_: &T) |
| 209 | where |
| 210 | T: Send + Sync + Unpin + UnwindSafe + RefUnwindSafe, |
| 211 | { |
| 212 | } |
| 213 | |
| 214 | make_guard!(a); |
| 215 | assert_oibits(&a); |
| 216 | let id: Id<'_> = a.into(); |
| 217 | assert_oibits(&id); |
| 218 | |
| 219 | // const compatible (e.g. const_refs_to_cell, const destructor) |
| 220 | const fn _const_id(_: Id<'_>) {} |
| 221 | const fn _const_ref_id(_: &'_ Id<'_>) {} |
| 222 | const fn _const_guard(_: Guard<'_>) {} |
| 223 | const fn _const_ref_guard(_: &'_ Guard<'_>) {} |
| 224 | } |
| 225 | } |
| 226 | |