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
43use core_::fmt;
44use core_::marker::PhantomData;
45
46#[doc(hidden)]
47/// NOT STABLE PUBLIC API. Previously Used by the expansion of [`make_guard!`].
48pub 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)]
60pub struct Id<'id> {
61 phantom: PhantomData<fn(&'id ()) -> &'id ()>,
62}
63
64impl<'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
82impl<'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
88impl<'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)]
101pub struct Guard<'id> {
102 #[allow(unused)]
103 id: Id<'id>,
104}
105
106impl<'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
122impl<'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!`].
130pub struct LifetimeBrand<'id> {
131 phantom: PhantomData<&'id Id<'id>>,
132}
133
134impl<'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!`].
148impl<'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]
176macro_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)]
194mod 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