movable_ref/combinators/self_ref_cell.rs
1use crate::offset::Nullable;
2use crate::{Offset, PointerRecomposition, SelfRef};
3
4/// Container that provides safe access to a self-referenced value.
5pub struct SelfRefCell<T: PointerRecomposition, I: Offset = isize> {
6 value: T,
7 ptr: SelfRef<T, I>,
8}
9
10impl<T: PointerRecomposition, I: Offset + Nullable> SelfRefCell<T, I> {
11 /// Creates a new cell.
12 ///
13 /// # Parameters
14 /// * `value` - Value to be owned by the cell and referenced internally.
15 ///
16 /// # Returns
17 /// * `Result<Self, I::Error>` - `Ok` with an initialised cell, or the offset error when `I`
18 /// cannot encode the distance.
19 pub fn new(value: T) -> Result<Self, I::Error> {
20 let mut this = Self {
21 value,
22 ptr: SelfRef::null(),
23 };
24 this.ptr.set(&mut this.value)?;
25 Ok(this)
26 }
27
28 /// Immutable access to the value.
29 ///
30 /// # Returns
31 /// * `&T` - Shared reference to the stored value.
32 pub fn get(&self) -> &T {
33 self.try_get()
34 .expect("SelfRefCell accessed before initialisation")
35 }
36
37 /// Immutable access to the value if the pointer has been initialised.
38 ///
39 /// # Returns
40 /// * `Option<&T>` - Shared reference when the pointer is ready.
41 #[inline]
42 pub fn try_get(&self) -> Option<&T> {
43 if !self.ptr.is_ready() {
44 return None;
45 }
46 let base = self as *const _ as *const u8;
47 Some(unsafe { self.ptr.get_ref_from_base_unchecked(base) })
48 }
49
50 /// Mutable access to the value.
51 ///
52 /// # Returns
53 /// * `&mut T` - Exclusive reference to the stored value.
54 pub fn get_mut(&mut self) -> &mut T {
55 self.try_get_mut()
56 .expect("SelfRefCell accessed before initialisation")
57 }
58
59 /// Mutable access to the value if the pointer has been initialised.
60 ///
61 /// # Returns
62 /// * `Option<&mut T>` - Exclusive reference when the pointer is ready.
63 #[inline]
64 pub fn try_get_mut(&mut self) -> Option<&mut T> {
65 if !self.ptr.is_ready() {
66 return None;
67 }
68 let base = self as *mut _ as *mut u8;
69 Some(unsafe { self.ptr.get_mut_from_base_unchecked(base) })
70 }
71
72 /// Consumes the cell and returns the value.
73 ///
74 /// # Returns
75 /// * `T` - The owned value.
76 pub fn into_inner(self) -> T {
77 self.value
78 }
79}