solana_stable_layout/
stable_vec.rs1use std::{
4 marker::PhantomData,
5 mem::ManuallyDrop,
6 ops::{Deref, DerefMut},
7};
8
9#[repr(C)]
30pub struct StableVec<T> {
31 pub addr: u64,
32 pub cap: u64,
33 pub len: u64,
34 _marker: PhantomData<T>,
35}
36
37impl<T> StableVec<T> {
40 #[inline]
41 pub fn as_vaddr(&self) -> u64 {
42 self.addr
43 }
44
45 #[inline]
46 pub fn len(&self) -> u64 {
47 self.len
48 }
49
50 #[inline]
51 pub fn is_empty(&self) -> bool {
52 self.len == 0
53 }
54}
55
56impl<T> AsRef<[T]> for StableVec<T> {
57 fn as_ref(&self) -> &[T] {
58 self.deref()
59 }
60}
61
62impl<T> AsMut<[T]> for StableVec<T> {
63 fn as_mut(&mut self) -> &mut [T] {
64 self.deref_mut()
65 }
66}
67
68impl<T> std::ops::Deref for StableVec<T> {
69 type Target = [T];
70
71 #[inline]
72 fn deref(&self) -> &[T] {
73 unsafe { core::slice::from_raw_parts(self.addr as usize as *mut T, self.len as usize) }
74 }
75}
76
77impl<T> std::ops::DerefMut for StableVec<T> {
78 #[inline]
79 fn deref_mut(&mut self) -> &mut [T] {
80 unsafe { core::slice::from_raw_parts_mut(self.addr as usize as *mut T, self.len as usize) }
81 }
82}
83
84impl<T: std::fmt::Debug> std::fmt::Debug for StableVec<T> {
85 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
86 std::fmt::Debug::fmt(&**self, f)
87 }
88}
89
90macro_rules! impl_partial_eq {
91 ([$($vars:tt)*] $lhs:ty, $rhs:ty) => {
92 impl<T, U, $($vars)*> PartialEq<$rhs> for $lhs
93 where
94 T: PartialEq<U>,
95 {
96 #[inline]
97 fn eq(&self, other: &$rhs) -> bool { self[..] == other[..] }
98 }
99 }
100}
101impl_partial_eq! { [] StableVec<T>, StableVec<U> }
102impl_partial_eq! { [] StableVec<T>, Vec<U> }
103impl_partial_eq! { [] Vec<T>, StableVec<U> }
104impl_partial_eq! { [] StableVec<T>, &[U] }
105impl_partial_eq! { [] StableVec<T>, &mut [U] }
106impl_partial_eq! { [] &[T], StableVec<U> }
107impl_partial_eq! { [] &mut [T], StableVec<U> }
108impl_partial_eq! { [] StableVec<T>, [U] }
109impl_partial_eq! { [] [T], StableVec<U> }
110impl_partial_eq! { [const N: usize] StableVec<T>, [U; N] }
111impl_partial_eq! { [const N: usize] StableVec<T>, &[U; N] }
112
113impl<T> From<Vec<T>> for StableVec<T> {
114 fn from(other: Vec<T>) -> Self {
115 let mut other = ManuallyDrop::new(other);
121 Self {
122 addr: other.as_mut_ptr() as u64, cap: other.capacity() as u64,
125 len: other.len() as u64,
126 _marker: PhantomData,
127 }
128 }
129}
130
131impl<T> From<StableVec<T>> for Vec<T> {
132 fn from(other: StableVec<T>) -> Self {
133 let other = ManuallyDrop::new(other);
136 unsafe {
141 Vec::from_raw_parts(
142 other.addr as usize as *mut T,
143 other.len as usize,
144 other.cap as usize,
145 )
146 }
147 }
148}
149
150impl<T> Drop for StableVec<T> {
151 fn drop(&mut self) {
152 let _vec = unsafe {
158 Vec::from_raw_parts(
159 self.addr as usize as *mut T,
160 self.len as usize,
161 self.cap as usize,
162 )
163 };
164 }
165}
166
167#[cfg(test)]
168mod tests {
169 use {
170 super::*,
171 memoffset::offset_of,
172 std::mem::{align_of, size_of},
173 };
174
175 #[test]
176 fn test_memory_layout() {
177 assert_eq!(offset_of!(StableVec<i32>, addr), 0);
178 assert_eq!(offset_of!(StableVec<i32>, cap), 8);
179 assert_eq!(offset_of!(StableVec<i32>, len), 16);
180 assert_eq!(align_of::<StableVec<i32>>(), 8);
181 assert_eq!(size_of::<StableVec<i32>>(), 8 + 8 + 8);
182
183 let vec = {
185 let mut vec = Vec::with_capacity(3);
186 vec.push(11);
187 vec.push(22);
188 vec
189 };
190 let vec = StableVec::from(vec);
191
192 let addr_vec = &vec as *const _ as usize;
193 let addr_ptr = addr_vec;
194 let addr_cap = addr_vec + 8;
195 let addr_len = addr_vec + 16;
196 assert_eq!(unsafe { *(addr_cap as *const usize) }, 3);
197 assert_eq!(unsafe { *(addr_len as *const usize) }, 2);
198
199 let ptr_data = addr_ptr as *const &[i32; 2];
200 assert_eq!(unsafe { *ptr_data }, &[11, 22]);
201 }
202}