potential_well/traits.rs
1//! [`Well`] and [`WellMut`] traits.
2use core::{
3 ops::{Deref, DerefMut},
4 pin::Pin,
5 ptr::NonNull,
6};
7
8#[cfg(feature = "alloc")]
9use {
10 crate::atomic::{PotentialAtomic, PotentialAtomicOption},
11 alloc::{boxed::Box, rc::Rc, sync::Arc},
12};
13
14/// Place that can store a smart pointer.
15///
16/// # Safety
17///
18/// Types that implement this trait assert that:
19///
20/// 1. The `insert` and `remove` methods are true inverses of each other with no side effects.
21/// 2. The pointer to the data is stable on [`Deref`] and [`DerefMut`] (if implemented), *and* this
22/// pointer is the same as the one that is returned by [`remove`].
23/// 3. The data may be read even when outside the well.
24/// 4. If [`DerefMut`] is implemented, the data may be mutated even when outside the well.
25///
26/// [`insert`]: Well::insert
27/// [`remove`]: Well::remove
28pub unsafe trait Well: Deref<Target: Sized> {
29 /// Put the data back into the well.
30 ///
31 /// # Safety
32 ///
33 /// The pointer passed to [`insert`] must previously have been received from [`remove`].
34 ///
35 /// [`insert`]: Well::insert
36 /// [`remove`]: Well::remove
37 unsafe fn insert(ptr: NonNull<Self::Target>) -> Self;
38
39 /// Take the data out of the well.
40 fn remove(self) -> NonNull<Self::Target>;
41}
42
43/// Implementation of trait alias that uses trait aliases.
44#[cfg(feature = "nightly")]
45macro_rules! trait_alias {
46 (
47 $(#[$attr:meta])*
48 $vis:vis trait $t:ident = ($($bound:tt)*);
49 ) => {
50 $(#[$attr])*
51 ///
52 /// Implemented as a trait alias with the `nightly` feature,
53 /// and an automatically-implemented trait otherwise.
54 $vis trait $t = $($bound)*;
55 }
56}
57
58/// Implementation of trait alias that uses traits.
59#[cfg(not(feature = "nightly"))]
60macro_rules! trait_alias {
61 (
62 $(#[$attr:meta])*
63 $vis:vis trait $t:ident = ($($bound:tt)*);
64 ) => {
65 $(#[$attr])*
66 ///
67 /// Implemented as a trait alias with the `nightly` feature,
68 /// and an automatically-implemented trait otherwise.
69 $vis trait $t: $($bound)* {}
70 impl<T: $($bound)*> $t for T {}
71 }
72}
73
74trait_alias! {
75 /// Alias for <code>[Well] + [DerefMut]</code>.
76 pub trait WellMut = (DerefMut + Well);
77}
78
79// SAFETY: A pointer in its almost-rawest form.
80unsafe impl<T> Well for &T {
81 #[inline]
82 unsafe fn insert(ptr: NonNull<T>) -> Self {
83 // SAFETY: Ensured by caller.
84 unsafe { ptr.as_ref() }
85 }
86
87 #[inline]
88 fn remove(self) -> NonNull<T> {
89 NonNull::from(self)
90 }
91}
92
93// SAFETY: A pointer in its almost-rawest form.
94unsafe impl<T> Well for Pin<&T> {
95 #[inline]
96 unsafe fn insert(ptr: NonNull<T>) -> Self {
97 // SAFETY: Ensured by caller.
98 unsafe { Pin::new_unchecked(ptr.as_ref()) }
99 }
100
101 #[inline]
102 fn remove(self) -> NonNull<T> {
103 NonNull::from(self.get_ref())
104 }
105}
106
107// SAFETY: A pointer in its almost-rawest form.
108unsafe impl<T> Well for &mut T {
109 #[inline]
110 unsafe fn insert(mut ptr: NonNull<T>) -> Self {
111 // SAFETY: Ensured by caller.
112 unsafe { ptr.as_mut() }
113 }
114
115 #[inline]
116 fn remove(self) -> NonNull<T> {
117 NonNull::from(self)
118 }
119}
120
121// SAFETY: A pointer in its almost-rawest form.
122unsafe impl<T> Well for Pin<&mut T> {
123 #[inline]
124 unsafe fn insert(mut ptr: NonNull<T>) -> Self {
125 // SAFETY: Ensured by caller.
126 unsafe { Pin::new_unchecked(ptr.as_mut()) }
127 }
128
129 #[inline]
130 fn remove(self) -> NonNull<T> {
131 // SAFETY: We can only get a pinned version back out of the well.
132 unsafe { NonNull::from(self.get_unchecked_mut()) }
133 }
134}
135
136#[cfg(any(test, feature = "alloc"))]
137// SAFETY: `Box` just wraps a pointer.
138unsafe impl<T> Well for Box<T> {
139 #[inline]
140 unsafe fn insert(ptr: NonNull<T>) -> Self {
141 // SAFETY: Ensured by caller.
142 unsafe { Box::from_raw(ptr.as_ptr()) }
143 }
144
145 #[inline]
146 fn remove(self) -> NonNull<T> {
147 // SAFETY: Box's pointer is always non-null.
148 unsafe { NonNull::new_unchecked(Box::into_raw(self)) }
149 }
150}
151
152#[cfg(any(test, feature = "alloc"))]
153// SAFETY: If we keep the pin, everything works out.
154unsafe impl<T> Well for Pin<Box<T>> {
155 #[inline]
156 unsafe fn insert(ptr: NonNull<T>) -> Self {
157 // SAFETY: Ensured by caller.
158 unsafe { Pin::new_unchecked(Box::from_raw(ptr.as_ptr())) }
159 }
160
161 #[inline]
162 fn remove(self) -> NonNull<T> {
163 // SAFETY: Box's pointer is always non-null, and we're not moving anything out of the box.
164 unsafe { NonNull::new_unchecked(Box::into_raw(Pin::into_inner_unchecked(self))) }
165 }
166}
167
168#[cfg(feature = "alloc")]
169// SAFETY: `Rc` accounts for the reference-counter offsets in `into_raw` and `from_raw`.
170unsafe impl<T> Well for Rc<T> {
171 #[inline]
172 unsafe fn insert(ptr: NonNull<T>) -> Self {
173 // SAFETY: Ensured by caller.
174 unsafe { Rc::from_raw(ptr.as_ptr()) }
175 }
176
177 #[inline]
178 fn remove(self) -> NonNull<T> {
179 // SAFETY: Rc's pointer is always non-null.
180 unsafe { NonNull::new_unchecked(Rc::into_raw(self).cast_mut()) }
181 }
182}
183
184#[cfg(feature = "alloc")]
185// SAFETY: If we keep the pin, everything works out.
186unsafe impl<T> Well for Pin<Rc<T>> {
187 #[inline]
188 unsafe fn insert(ptr: NonNull<T>) -> Self {
189 // SAFETY: Ensured by caller.
190 unsafe { Pin::new_unchecked(Rc::from_raw(ptr.as_ptr())) }
191 }
192
193 #[inline]
194 fn remove(self) -> NonNull<T> {
195 // SAFETY: Rc's pointer is always non-null, and we're not moving anything out of the `Rc`.
196 unsafe { NonNull::new_unchecked(Rc::into_raw(Pin::into_inner_unchecked(self)).cast_mut()) }
197 }
198}
199
200#[cfg(feature = "alloc")]
201// SAFETY: `Arc` accounts for the reference-counter offsets in `into_raw` and `from_raw`.
202unsafe impl<T> Well for Arc<T> {
203 #[inline]
204 unsafe fn insert(ptr: NonNull<T>) -> Self {
205 // SAFETY: Ensured by caller.
206 unsafe { Arc::from_raw(ptr.as_ptr()) }
207 }
208
209 #[inline]
210 fn remove(self) -> NonNull<T> {
211 // SAFETY: Arc's pointer is always non-null.
212 unsafe { NonNull::new_unchecked(Arc::into_raw(self).cast_mut()) }
213 }
214}
215
216#[cfg(feature = "alloc")]
217// SAFETY: If we keep the pin, everything works out.
218unsafe impl<T> Well for Pin<Arc<T>> {
219 #[inline]
220 unsafe fn insert(ptr: NonNull<T>) -> Self {
221 // SAFETY: Ensured by caller.
222 unsafe { Pin::new_unchecked(Arc::from_raw(ptr.as_ptr())) }
223 }
224
225 #[inline]
226 fn remove(self) -> NonNull<T> {
227 // SAFETY: Arc's pointer is always non-null, and we're not moving anything out of the `Arc`.
228 unsafe { NonNull::new_unchecked(Arc::into_raw(Pin::into_inner_unchecked(self)).cast_mut()) }
229 }
230}
231
232/// Potential well, representing a generic container.
233///
234/// Useful for recursive data structures, since it avoids recursive types.
235///
236/// # Examples
237///
238/// Atomic linked list via [`PotentialWell`]:
239///
240/// ```
241/// use potential_well::{PotentialWell, PotentialAtomicOption};
242///
243/// struct Link<T, W: PotentialWell = Box<()>> {
244/// data: T,
245/// next: PotentialAtomicOption<Link<T, W>, W>
246/// }
247/// struct List<T, W: PotentialWell = Box<()>> {
248/// root: PotentialAtomicOption<Link<T, W>, W>,
249/// }
250///
251/// let list: List<u32> = List {
252/// root: PotentialAtomicOption::some(Box::new(Link {
253/// data: 1,
254/// next: PotentialAtomicOption::some(Box::new(Link {
255/// data: 2,
256/// next: PotentialAtomicOption::some(Box::new(Link {
257/// data: 3,
258/// next: PotentialAtomicOption::none(),
259/// }))
260/// })),
261/// })),
262/// };
263///
264/// // no Drop implementation needed!
265/// drop(list);
266/// ```
267///
268/// Without [`PotentialWell`], you immediately run into trouble:
269///
270/// ```compile_fail
271/// use potential_well::{Well, AtomicOption};
272///
273/// // recursive type: Link<T, Box<Link<T, Box<Link<T, ...>>>>>
274/// struct Link<T, W: Well<Target = Link<T, Self>>> {
275/// data: T,
276/// next: AtomicOption<W>,
277/// }
278/// struct List<T, W: Well<Target = Link<T, Self>>> {
279/// root: AtomicOption<W>,
280/// }
281///
282/// let list: List<u32, Box<_>> = List {
283/// root: AtomicOption::some(Box::new(Link {
284/// data: 1,
285/// next: AtomicOption::some(Box::new(Link {
286/// data: 2,
287/// next: AtomicOption::some(Box::new(Link {
288/// data: 3,
289/// next: AtomicOption::none(),
290/// }))
291/// })),
292/// })),
293/// };
294/// ```
295pub trait PotentialWell {
296 /// Makes a well of a particular type.
297 type Well<T>: Well<Target = T>;
298
299 /// Makes that well.
300 fn new<T>(data: T) -> Self::Well<T>;
301}
302
303#[cfg(any(test, feature = "alloc"))]
304impl PotentialWell for Box<()> {
305 type Well<T> = Box<T>;
306
307 #[inline]
308 fn new<T>(data: T) -> Box<T> {
309 Box::new(data)
310 }
311}
312
313#[cfg(any(test, feature = "alloc"))]
314impl PotentialWell for Pin<Box<()>> {
315 type Well<T> = Pin<Box<T>>;
316
317 #[inline]
318 fn new<T>(data: T) -> Pin<Box<T>> {
319 Box::pin(data)
320 }
321}
322
323#[cfg(feature = "alloc")]
324impl PotentialWell for Rc<()> {
325 type Well<T> = Rc<T>;
326
327 #[inline]
328 fn new<T>(data: T) -> Rc<T> {
329 Rc::new(data)
330 }
331}
332
333#[cfg(feature = "alloc")]
334impl PotentialWell for Pin<Rc<()>> {
335 type Well<T> = Pin<Rc<T>>;
336
337 #[inline]
338 fn new<T>(data: T) -> Pin<Rc<T>> {
339 Rc::pin(data)
340 }
341}
342
343#[cfg(feature = "alloc")]
344impl PotentialWell for Arc<()> {
345 type Well<T> = Arc<T>;
346
347 #[inline]
348 fn new<T>(data: T) -> Arc<T> {
349 Arc::new(data)
350 }
351}
352
353#[cfg(feature = "alloc")]
354impl PotentialWell for Pin<Arc<()>> {
355 type Well<T> = Pin<Arc<T>>;
356
357 #[inline]
358 fn new<T>(data: T) -> Pin<Arc<T>> {
359 Arc::pin(data)
360 }
361}
362
363/// Gets a well from a [`PotentialWell`].
364///
365/// In case you haven't gotten the joke by now, an "atom in a box" is called a [potential well] in
366/// physics, and well, kinetic energy is the opposite of potential energy.
367///
368/// It's a bad joke. But this type shouldn't be necessary unless you're writing *really* generic
369/// code, since most of the time, you'll be using one of the many aliases for [`PotentialAtomic`]
370/// and [`PotentialAtomicOption`], which will just turn something like
371/// <code>[KineticWell]<T, W<()>></code> into <code>W<T></code>.
372///
373/// [potential well]: https://en.wikipedia.org/wiki/Potential_well
374pub type KineticWell<T, W> = <W as PotentialWell>::Well<T>;
375
376/// Alias for <code>[PotentialAtomic]<T, [Box]<()>></code>
377#[cfg(feature = "alloc")]
378pub type AtomicBox<T> = PotentialAtomic<T, Box<()>>;
379
380/// Alias for <code>[PotentialAtomic]<T, [Pin]<[Box]<()>>></code>
381#[cfg(feature = "alloc")]
382pub type AtomicPinBox<T> = PotentialAtomic<T, Pin<Box<()>>>;
383
384/// Alias for <code>[PotentialAtomic]<T, [Rc]<()>></code>
385#[cfg(feature = "alloc")]
386pub type AtomicRc<T> = PotentialAtomic<T, Rc<()>>;
387
388/// Alias for <code>[PotentialAtomic]<T, [Pin]<[Rc]<()>>></code>
389#[cfg(feature = "alloc")]
390pub type AtomicPinRc<T> = PotentialAtomic<T, Pin<Rc<()>>>;
391
392/// Alias for <code>[PotentialAtomic]<T, [Arc]<()>></code>
393#[cfg(feature = "alloc")]
394pub type AtomicArc<T> = PotentialAtomic<T, Arc<()>>;
395
396/// Alias for <code>[PotentialAtomic]<T, [Pin]<[Arc]<()>>></code>
397#[cfg(feature = "alloc")]
398pub type AtomicPinArc<T> = PotentialAtomic<T, Pin<Arc<()>>>;
399
400/// Alias for <code>[PotentialAtomicOption]<T, [Box]<()>></code>
401#[cfg(feature = "alloc")]
402pub type AtomicOptionBox<T> = PotentialAtomicOption<T, Box<()>>;
403
404/// Alias for <code>[PotentialAtomicOption]<T, [Pin]<[Box]<()>>></code>
405#[cfg(feature = "alloc")]
406pub type AtomicOptionPinBox<T> = PotentialAtomicOption<T, Pin<Box<()>>>;
407
408/// Alias for <code>[PotentialAtomicOption]<T, [Rc]<()>></code>
409#[cfg(feature = "alloc")]
410pub type AtomicOptionRc<T> = PotentialAtomicOption<T, Rc<()>>;
411
412/// Alias for <code>[PotentialAtomicOption]<T, [Pin]<[Rc]<()>>></code>
413#[cfg(feature = "alloc")]
414pub type AtomicOptionPinRc<T> = PotentialAtomicOption<T, Pin<Rc<()>>>;
415
416/// Alias for <code>[PotentialAtomicOption]<T, [Arc]<()>></code>
417#[cfg(feature = "alloc")]
418pub type AtomicOptionArc<T> = PotentialAtomicOption<T, Arc<()>>;
419
420/// Alias for <code>[PotentialAtomicOption]<T, [Pin]<[Arc]<()>>></code>
421#[cfg(feature = "alloc")]
422pub type AtomicOptionPinArc<T> = PotentialAtomicOption<T, Pin<Arc<()>>>;