ic_stable_memory/primitive/
s_ref_mut.rs

1use crate::encoding::AsFixedSizeBytes;
2use crate::primitive::StableType;
3use candid::types::{Serializer, Type};
4use candid::CandidType;
5use std::cell::UnsafeCell;
6use std::marker::PhantomData;
7use std::ops::{Deref, DerefMut};
8
9/// Mutable reference to data stored in stable memory
10///
11/// See also [SRef](crate::primitive::s_ref::SRef).
12///
13/// Lazy on reads  - only loads and deserializes the data, when it gets accessed. Lazy on writes -
14/// only performs actual underlying data updates when [Drop]-ped. Useful when building your
15/// own stable data structure. Immutable and mutable access is provided by dereferencing.
16///
17/// `T` has to implement [StableType] and [AsFixedSizeBytes].
18pub struct SRefMut<'o, T: StableType + AsFixedSizeBytes> {
19    ptr: u64,
20    inner: UnsafeCell<Option<T>>,
21    _marker: PhantomData<&'o mut T>,
22}
23
24impl<'o, T: StableType + AsFixedSizeBytes> SRefMut<'o, T> {
25    /// Creates mutable reference from raw pointer.
26    ///
27    /// # Safety
28    /// Make sure your raw pointer points to a valid location.
29    #[inline]
30    pub unsafe fn new(ptr: u64) -> Self {
31        Self {
32            ptr,
33            inner: UnsafeCell::new(None),
34            _marker: PhantomData::default(),
35        }
36    }
37
38    #[inline]
39    unsafe fn read(&self) {
40        if (*self.inner.get()).is_none() {
41            let it = crate::mem::read_fixed_for_move(self.ptr);
42            *self.inner.get() = Some(it);
43        }
44    }
45
46    #[inline]
47    unsafe fn repersist(&mut self) {
48        if let Some(it) = self.inner.get_mut() {
49            crate::mem::write_fixed(self.ptr, it);
50        }
51    }
52}
53
54impl<'o, T: StableType + AsFixedSizeBytes> Deref for SRefMut<'o, T> {
55    type Target = T;
56
57    #[inline]
58    fn deref(&self) -> &Self::Target {
59        unsafe {
60            self.read();
61
62            (*self.inner.get()).as_ref().unwrap()
63        }
64    }
65}
66
67impl<'o, T: StableType + AsFixedSizeBytes> DerefMut for SRefMut<'o, T> {
68    #[inline]
69    fn deref_mut(&mut self) -> &mut Self::Target {
70        unsafe { self.read() };
71
72        self.inner.get_mut().as_mut().unwrap()
73    }
74}
75
76impl<'o, T: StableType + AsFixedSizeBytes> Drop for SRefMut<'o, T> {
77    #[inline]
78    fn drop(&mut self) {
79        unsafe { self.repersist() };
80    }
81}
82
83impl<'o, T: StableType + AsFixedSizeBytes + CandidType> CandidType for SRefMut<'o, T> {
84    #[inline]
85    fn _ty() -> Type {
86        T::_ty()
87    }
88
89    #[inline]
90    fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
91    where
92        S: Serializer,
93    {
94        unsafe {
95            self.read();
96
97            (*self.inner.get())
98                .as_ref()
99                .unwrap()
100                .idl_serialize(serializer)
101        }
102    }
103}