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}