singleton_trait/
lib.rs

1#![doc(html_root_url = "https://docs.rs/singleton-trait/0.4.0")]
2#![no_std]
3
4use core::cell::{Cell, UnsafeCell};
5use core::marker::PhantomData;
6use core::mem::ManuallyDrop;
7
8/*******************/
9/* Singleton trait */
10/*******************/
11
12/**
13 * This trait denotes a type which has at most one logical identity at all times.
14 * This is sufficient to make borrowing decisions based only on the type, without
15 * regards to value identity.
16 *
17 * Implementers of the trait must uphold this contract, that any point
18 * during the execution of the program, there is at most one accessible
19 * logical value of this type. Much like how re-borrowings can
20 * make a type inaccessible, it is allowed for there to be more than one
21 * such binding, if the others are inaccessible due to unique borrowing.
22 *
23 * Some examples would include:
24 * * A type with exactly one instance constructed during the main method
25 * * A type with only one static instance (including one wrapped behind e.g. a Mutex)
26 * * An uninhabited type
27 * * A type which is constructed with a unique lifetime brand
28 *
29 * Any type which has a public constructor cannot meet this,
30 * Some non-examples include ZSTs like ()
31 * and the Exists<T> struct in this crate (when T is not a Singleton itself)
32 * Any type which implements Clone
33 */
34pub unsafe trait Singleton {}
35
36/*****************/
37/* Blanket Impls */
38/*****************/
39
40// Anything which is backed by at least one T
41// can be given an implementation
42//
43// This can be witnessed by a function
44// S -> T where T is a singleton
45
46// SAFETY:
47// These types are all backed by exactly one, unique T
48unsafe impl<T: Singleton> Singleton for Cell<T> {}
49unsafe impl<T: Singleton> Singleton for UnsafeCell<T> {}
50unsafe impl<T: Singleton> Singleton for [T; 1] {}
51// Not many other interesting cases, but some like Box require alloc
52
53// SAFETY:
54// 1. Every mutable reference points to a value of T
55// 2. No two mutable references alias
56// 3. By the contract of Singleton for T, there is at most one logical value of T
57unsafe impl<'a, T: Singleton> Singleton for &'a mut T {}
58// SAFETY:
59// Exists<T> witnesses strict ownership of a value of type T
60unsafe impl<'a, T: Singleton> Singleton for Erased<T> {}
61
62/*******************/
63/* Single-threaded */
64/*******************/
65
66/**
67 * A type `T` implements SingleThread if at any time there
68 * is a single thread from which all values/references to
69 * values of this type may be accessed.
70 *
71 * Usually, it is sufficient that `T` is `!Sync` and `Singleton`.
72 *
73 * Since Sending `T` denies access in the original thread, this
74 * property is maintained regardless of Sendability.
75 */
76pub unsafe trait SingleThread { }
77
78/*****************/
79/* Blanket Impls */
80/*****************/
81
82// SAFETY:
83// These cases are structurally Sync
84unsafe impl<T: SingleThread> SingleThread for Cell<T> {}
85unsafe impl<T: SingleThread> SingleThread for [T; 1] {}
86// other interesting cases generally require alloc, or could be changed.
87
88// SAFETY:
89// From `&&mut T` we can produce `&T`, and by the contract for
90// T: SingleThread, this is locked to one thread, so
91// we can assume that `&&mut T` is also locked to one thread
92unsafe impl<'a, T: SingleThread> SingleThread for &'a mut T {}
93unsafe impl<'a, T: SingleThread> SingleThread for &'a T {}
94
95// SAFETY:
96// Exists<T> witnesses strict ownership of a value of type T
97unsafe impl<'a, T: SingleThread> SingleThread for Erased<T> {}
98
99/*********************/
100/* Phantom existence */
101/*********************/
102
103/**
104 * The Erased struct witnesses the logical ownership of a value of type T
105 * while remaining zero-sized. This can be used for ghost proofs of soundness.
106 *
107 * Erased<T> should be thought of a zero-sized owner of T. It is useful for inclusion
108 * in data structures where the value might not be eliminated by the compiler.
109 * It likely is not necessary for short-lived data.
110 *
111 * NOTE: drop implementations will never be called, as Exists<T> guarantees the existence
112 * of a valid T, which might not be true if they were called. On the other hand, since
113 * it does not hold a T, it cannot drop T when it is itself dropped
114 *
115 * Secondly, keep in mind that while Erased<T> serves as evidence, it does not include
116 * sufficient provenance for Stacked Borrows or LLVM, and so it is not techinically sound
117 * to recover a reference `&T` from an `Exists<&T>` and `*mut T` or `&UnsafeCell<T>`
118 * even when T is Singleton, but this could be possible if T is zero-sized.
119 * Because of the missing provenance, creating a reference this way could invalidate
120 * the original reference on which this Exists instance was based.
121 */
122#[derive(Copy)]
123pub struct Erased<T> {
124    _phantom: PhantomData<ManuallyDrop<T>>,
125}
126impl<T: Copy> Clone for Erased<T> {
127    #[inline(always)]
128    fn clone(&self) -> Self {
129        *self
130    }
131}
132impl<T> Erased<T> {
133    #[inline(always)]
134    pub const fn new(t: T) -> Self {
135        let _ = ManuallyDrop::new(t);
136        // SAFETY: we have taken ownership of a T value above
137        unsafe { Self::new_unchecked() }
138    }
139
140    /**
141     * This function constructs a value of Erased<T> without taking logical ownership of a T.
142     *
143     * # Safety
144     *
145     * Constructing this asserts that there is a value of type T which has been leaked, or
146     * in which it is guaranteed that the program behaves the same up to observation as if a
147     * zero-sized copy of T were being passed.
148     *
149     */
150    #[inline(always)]
151    pub const unsafe fn new_unchecked() -> Self {
152        Erased {
153            _phantom: PhantomData,
154        }
155    }
156
157    /**
158     * Turns a &Erased<T> into an Erased<&T>
159     *
160     * This can be especially useful when storing
161     * the Erased<T> inside another wrapper type
162     *
163     * ```
164     * # use singleton_trait::Erased;
165     * use core::cell::RefCell;
166     * struct Token;
167     * let lock = RefCell::new(Erased::new(Token));
168     *
169     * let locked = lock.borrow();
170     * let _: Erased<&Token> = locked.borrow();
171     * ```
172     */
173    #[inline(always)]
174    pub fn borrow(&self) -> Erased<&T> {
175        // Safety:
176        // the identity function is pure
177        unsafe { self.map_borrow(|r| r) }
178    }
179
180    /**
181     * Turns a &mut Erased<T> into an Erased<&mut T>
182     *
183     * This can be especially useful when storing
184     * the Erased<T> inside another wrapper type
185     *
186     * ```
187     * # use singleton_trait::Erased;
188     * use core::cell::RefCell;
189     * struct Token;
190     * let lock = RefCell::new(Erased::new(Token));
191     *
192     * let mut locked = lock.borrow_mut();
193     * let _: Erased<&mut Token> = locked.borrow_mut();
194     * ```
195     */
196    #[inline(always)]
197    pub fn borrow_mut(&mut self) -> Erased<&mut T> {
198        // Safety:
199        // the identity function is pure
200        unsafe { self.map_borrow_mut(|r| r) }
201    }
202
203    /**
204     * Maps a function on the inside of the Erased field.
205     *
206     * # Safety
207     *
208     * Due to the strictness guarantees, the passed closure must not cause any visible
209     * side effects, including side effects caused by owning R
210     */
211    #[inline(always)]
212    pub unsafe fn map<R, F: FnOnce(T) -> R>(self, _: impl Exists<F>) -> Erased<R> {
213        // Safety:
214        //
215        // By the contract for the passed function, this is equivalent to calling it on the value of type T
216        Erased::<R>::new_unchecked()
217    }
218
219    /**
220     * Maps a function on the borrow of the Erased field.
221     *
222     * # Safety
223     *
224     * Due to the strictness guarantees, the passed closure must not cause any visible
225     * side effects, including side effects caused by owning R
226     */
227    #[inline(always)]
228    pub unsafe fn map_borrow<'a, R, F: FnOnce(&'a T) -> R>(
229        &'a self,
230        _: impl Exists<F>,
231    ) -> Erased<R> {
232        // Safety:
233        //
234        // By the contract for the passed function, this is equivalent to calling it on the borrow of T
235        Erased::<R>::new_unchecked()
236    }
237    /**
238     * Maps a function on the mutable borrow of the Erased field.
239     *
240     * # Safety
241     *
242     * Due to the strictness guarantees, the passed closure must not cause any visible
243     * side effects, including side effects caused by owning R
244     */
245    #[inline(always)]
246    pub unsafe fn map_borrow_mut<'a, R, F: FnOnce(&'a mut T) -> R>(
247        &'a mut self,
248        _: impl Exists<F>,
249    ) -> Erased<R> {
250        // Safety:
251        //
252        // By the contract for the passed function, this is equivalent to calling it on the mutable borrow of T
253        Erased::<R>::new_unchecked()
254    }
255
256    /**
257     * Fallback function which converts this Erased value into an Exists
258     * implementer.
259     *
260     * This exists because we cannot allow general trait implementations
261     * due to coherence rules, but we can't be sufficiently flexible in
262     * trait implementations due to a lack of subtyping constraints or
263     * trait covariance, which would mean references would be too inflexible
264     */
265    #[inline(always)]
266    pub fn exists(self) -> impl Exists<T> {
267        struct Internal<T> {
268            er: Erased<T>,
269        }
270        impl<T> Exists<T> for Internal<T> {
271            #[inline(always)]
272            fn erase(self) -> Erased<T> {
273                self.er
274            }
275        }
276        Internal { er: self }
277    }
278}
279impl<T> Erased<Erased<T>> {
280    /**
281     * An erased erased value can be flattened into a single erasure,
282     * since Erased<T> is notionally equivalent to T
283     */
284    #[inline(always)]
285    pub fn flatten(self) -> Erased<T> {
286        // SAFETY:
287        //
288        // By existential induction since the constructor for Erased is pure
289        unsafe { Erased::<T>::new_unchecked() }
290    }
291}
292impl<'a, T> Erased<&'a mut T> {
293    /**
294     * Re-borrow this erased mutable borrow. Usually
295     * this is implicit in Rust, but not for general wrappers.
296     * This can be seen as a "clone" method for mutable borrows,
297     * as it allows you to retain the erased borrow after the
298     * end of the lifetime.
299     *
300     * The Exists trait can perform this conversion automatically.
301     *
302     * ```
303     * # use singleton_trait::Erased;
304     * struct Token;
305     * fn recursively(mut b: Erased<&mut Token>) {
306     *  recursively(b.reborrow());
307     *  recursively(b);
308     * }
309     * ```
310     */
311    #[inline(always)]
312    pub fn reborrow<'b>(&'b mut self) -> Erased<&'b mut T> {
313        // SAFETY
314        //
315        // Refs and derefs on reference types are pure
316        unsafe { self.map_borrow_mut(|r: &'b mut &'a mut T| &mut **r) }
317    }
318
319    /**
320     * Borrow this erased mutable borrow as immutable.
321     * This is effectively a Deref method under Erased
322     *
323     * The Exists trait can perform this conversion automatically.
324     *
325     * ```
326     * # use singleton_trait::Erased;
327     * struct Lock;
328     * fn use_lock(write: Erased<&mut Lock>) {
329     *   read_from(write.read());
330     * }
331     *
332     * fn read_from(read: Erased<&Lock>) { }
333     * ```
334     */
335    #[inline(always)]
336    pub fn read<'b>(&'b self) -> Erased<&'b T> {
337        // SAFETY
338        //
339        // Refs and derefs on reference types are pure
340        unsafe { self.map_borrow(|r: &'b &'a mut T| &**r) }
341    }
342
343    /**
344     * Consume this erased mutable borrow to
345     * turn it into an immutable borrow.
346     *
347     * The Exists trait can perform this conversion automatically.
348     *
349     * See also `read`, which is often more useful.
350     * This method uses the full inner lifetime
351     * without needing to borrow.
352     * ```
353     * # use singleton_trait::Erased;
354     * struct Lock;
355     * struct MutWrapper<'a> (Erased<&'a mut Lock>);
356     * struct Wrapper<'a> (Erased<&'a Lock>);
357     * impl<'a> MutWrapper<'a> {
358     *   pub fn into_read(self) -> Wrapper<'a> {
359     *      Wrapper(self.0.into_shared())
360     *   }
361     * }
362     *
363     * ```
364     */
365    #[inline(always)]
366    pub fn into_shared(self) -> Erased<&'a T> {
367        // SAFETY
368        //
369        // Refs and derefs on reference types are pure
370        unsafe { self.map(|r: &'a mut T| &*r) }
371    }
372}
373impl<T> From<T> for Erased<T> {
374    #[inline(always)]
375    fn from(t: T) -> Self {
376        Self::new(t)
377    }
378}
379/**
380 * The Exists trait is intended to be used with `impl`, to denote
381 * an argument where the existence of a value is sufficient as an argument
382 *
383 *
384 */
385pub trait Exists<T: Sized> {
386    fn erase(self) -> Erased<T>;
387}
388impl<T> Exists<T> for T {
389    #[inline(always)]
390    fn erase(self) -> Erased<T> {
391        self.into()
392    }
393}
394
395impl<'a, 'b: 'a, T> Exists<&'a T> for Erased<&'b T> {
396    #[inline(always)]
397    fn erase(self) -> Erased<&'a T> {
398        self
399    }
400}
401impl<'a, 'b: 'a, T> Exists<&'a T> for Erased<&'b mut T> {
402    #[inline(always)]
403    fn erase(self) -> Erased<&'a T> {
404        self.into_shared()
405    }
406}
407impl<'a, 'b: 'a, T> Exists<&'a mut T> for Erased<&'b mut T> {
408    #[inline(always)]
409    fn erase(self) -> Erased<&'a mut T> {
410        // SAFETY: Deref on reference is pure
411        unsafe { self.map(|r: &'a mut T| &mut *r) }
412    }
413}
414impl<'a, 'b, T> Exists<&'a T> for &'a Erased<&'b T> {
415    #[inline(always)]
416    fn erase(self) -> Erased<&'a T> {
417        *self
418    }
419}
420impl<'a, 'b: 'a, T> Exists<&'a T> for &'a Erased<&'b mut T> {
421    #[inline(always)]
422    fn erase(self) -> Erased<&'a T> {
423        // SAFETY: Deref on reference is pure
424        self.read()
425    }
426}
427impl<'a, 'b: 'a, T> Exists<&'a mut T> for &'a mut Erased<&'b mut T> {
428    #[inline(always)]
429    fn erase(self) -> Erased<&'a mut T> {
430        // SAFETY: Deref on reference is pure
431        self.reborrow()
432    }
433}
434
435#[cfg(test)]
436mod tests {
437    use crate::*;
438
439    // this test should fail to compile if we're missing impls
440    // that can coerce between different lifetimes
441    #[test]
442    fn test_impls() {
443        /* Invariant type parameter to strictly test subtyping */
444        struct NonCopy;
445        impl Drop for NonCopy {
446            fn drop(&mut self) {}
447        }
448        struct Guard<'a>(PhantomData<fn(&'a ()) -> &'a ()>, &'a NonCopy);
449
450        fn takes_ref<'a>(_: &Guard<'a>, _: impl Exists<&'a ()>) {}
451        fn takes_mut<'a>(_: &Guard<'a>, _: impl Exists<&'a mut ()>) {}
452
453        let nc = NonCopy;
454        let guard = Guard(PhantomData, &nc);
455
456        let er = Erased::new(&());
457        takes_ref(&guard, er);
458
459        let mut x = ();
460        let er = Erased::new(&mut x);
461        takes_ref(&guard, er);
462
463        let mut x = ();
464        let er = Erased::new(&mut x);
465        takes_mut(&guard, er);
466    }
467}