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}