solana_stable_layout/
stable_vec.rs

1//! `Vec`, with a stable memory layout
2
3use std::{marker::PhantomData, mem::ManuallyDrop, ptr::NonNull};
4
5/// `Vec`, with a stable memory layout
6///
7/// This container is used within the runtime to ensure memory mapping and memory accesses are
8/// valid.  We rely on known addresses and offsets within the runtime, and since `Vec`'s layout
9/// is allowed to change, we must provide a way to lock down the memory layout.  `StableVec`
10/// reimplements the bare minimum of `Vec`'s API sufficient only for the runtime's needs.
11///
12/// To ensure memory allocation and deallocation is handled correctly, it is only possible to
13/// create a new `StableVec` from an existing `Vec`.  This way we ensure all Rust invariants are
14/// upheld.
15///
16/// # Examples
17///
18/// Creating a `StableVec` from a `Vec`
19///
20/// ```
21/// # use solana_stable_layout::stable_vec::StableVec;
22/// let vec = vec!["meow", "woof", "moo"];
23/// let vec = StableVec::from(vec);
24/// ```
25#[repr(C)]
26pub struct StableVec<T> {
27    pub ptr: NonNull<T>,
28    pub cap: usize,
29    pub len: usize,
30    _marker: PhantomData<T>,
31}
32
33// We shadow these slice methods of the same name to avoid going through
34// `deref`, which creates an intermediate reference.
35impl<T> StableVec<T> {
36    #[inline]
37    pub fn as_ptr(&self) -> *const T {
38        self.ptr.as_ptr()
39    }
40
41    #[inline]
42    pub fn as_mut_ptr(&mut self) -> *mut T {
43        self.ptr.as_ptr()
44    }
45
46    #[inline]
47    pub fn len(&self) -> usize {
48        self.len
49    }
50
51    #[inline]
52    pub fn is_empty(&self) -> bool {
53        self.len == 0
54    }
55}
56
57impl<T> AsRef<[T]> for StableVec<T> {
58    fn as_ref(&self) -> &[T] {
59        self
60    }
61}
62
63impl<T> AsMut<[T]> for StableVec<T> {
64    fn as_mut(&mut self) -> &mut [T] {
65        self
66    }
67}
68
69impl<T> std::ops::Deref for StableVec<T> {
70    type Target = [T];
71
72    #[inline]
73    fn deref(&self) -> &[T] {
74        unsafe { core::slice::from_raw_parts(self.as_ptr(), self.len) }
75    }
76}
77
78impl<T> std::ops::DerefMut for StableVec<T> {
79    #[inline]
80    fn deref_mut(&mut self) -> &mut [T] {
81        unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr(), self.len) }
82    }
83}
84
85impl<T: std::fmt::Debug> std::fmt::Debug for StableVec<T> {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        std::fmt::Debug::fmt(&**self, f)
88    }
89}
90
91macro_rules! impl_partial_eq {
92    ([$($vars:tt)*] $lhs:ty, $rhs:ty) => {
93        impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
94        where
95            T: PartialEq<U>,
96        {
97            #[inline]
98            fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
99        }
100    }
101}
102impl_partial_eq! { [] StableVec<T>, StableVec<U> }
103impl_partial_eq! { [] StableVec<T>, Vec<U> }
104impl_partial_eq! { [] Vec<T>, StableVec<U> }
105impl_partial_eq! { [] StableVec<T>, &[U] }
106impl_partial_eq! { [] StableVec<T>, &mut [U] }
107impl_partial_eq! { [] &[T], StableVec<U> }
108impl_partial_eq! { [] &mut [T], StableVec<U> }
109impl_partial_eq! { [] StableVec<T>, [U] }
110impl_partial_eq! { [] [T], StableVec<U> }
111impl_partial_eq! { [const N: usize] StableVec<T>, [U; N] }
112impl_partial_eq! { [const N: usize] StableVec<T>, &[U; N] }
113
114impl<T> From<Vec<T>> for StableVec<T> {
115    fn from(other: Vec<T>) -> Self {
116        // NOTE: This impl is basically copied from `Vec::into_raw_parts()`.  Once that fn is
117        // stabilized, use it here.
118        //
119        // We are going to pilfer `other`'s guts, and we don't want it to be dropped when it goes
120        // out of scope.
121        let mut other = ManuallyDrop::new(other);
122        Self {
123            // SAFETY: We have a valid Vec, so its ptr is non-null.
124            ptr: unsafe { NonNull::new_unchecked(other.as_mut_ptr()) },
125            cap: other.capacity(),
126            len: other.len(),
127            _marker: PhantomData,
128        }
129    }
130}
131
132impl<T> From<StableVec<T>> for Vec<T> {
133    fn from(other: StableVec<T>) -> Self {
134        // We are going to pilfer `other`'s guts, and we don't want it to be dropped when it goes
135        // out of scope.
136        let other = ManuallyDrop::new(other);
137        // SAFETY: We have a valid StableVec, which we can only get from a Vec.  Therefore it is
138        // safe to convert back to Vec.
139        unsafe { Vec::from_raw_parts(other.ptr.as_ptr(), other.len, other.cap) }
140    }
141}
142
143impl<T> Drop for StableVec<T> {
144    fn drop(&mut self) {
145        // We only allow creating a StableVec through creating a Vec.  To ensure we are dropped
146        // correctly, convert ourselves back to a Vec and let Vec's drop handling take over.
147        //
148        // SAFETY: We have a valid StableVec, which we can only get from a Vec.  Therefore it is
149        // safe to convert back to Vec.
150        let _vec = unsafe { Vec::from_raw_parts(self.ptr.as_ptr(), self.len, self.cap) };
151    }
152}
153
154#[cfg(test)]
155mod tests {
156    use {
157        super::*,
158        memoffset::offset_of,
159        std::mem::{align_of, size_of},
160    };
161
162    #[test]
163    fn test_memory_layout() {
164        assert_eq!(offset_of!(StableVec<i32>, ptr), 0);
165        assert_eq!(offset_of!(StableVec<i32>, cap), 8);
166        assert_eq!(offset_of!(StableVec<i32>, len), 16);
167        assert_eq!(align_of::<StableVec<i32>>(), 8);
168        assert_eq!(size_of::<StableVec<i32>>(), 8 + 8 + 8);
169
170        // create a vec with different values for cap and len
171        let vec = {
172            let mut vec = Vec::with_capacity(3);
173            vec.push(11);
174            vec.push(22);
175            vec
176        };
177        let vec = StableVec::from(vec);
178
179        let addr_vec = &vec as *const _ as usize;
180        let addr_ptr = addr_vec;
181        let addr_cap = addr_vec + 8;
182        let addr_len = addr_vec + 16;
183        assert_eq!(unsafe { *(addr_cap as *const usize) }, 3);
184        assert_eq!(unsafe { *(addr_len as *const usize) }, 2);
185
186        let ptr_data = addr_ptr as *const &[i32; 2];
187        assert_eq!(unsafe { *ptr_data }, &[11, 22]);
188    }
189}