ic_stable_memory/primitive/
s_ref.rs

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