cel_runtime/raw_vec.rs
1use crate::memory::align_index;
2use std::cmp::max;
3use std::mem::MaybeUninit;
4use std::ops::{Index, IndexMut};
5use std::slice::SliceIndex;
6
7/// A vector of bytes aligned to a given value. The alignment can be increase by calling `align`.
8#[derive(Debug)]
9pub struct RawVec {
10 buffer: Vec<MaybeUninit<u8>>,
11 base_alignment: usize,
12 start_offset: usize,
13}
14
15impl<I> Index<I> for RawVec
16where
17 I: SliceIndex<[MaybeUninit<u8>]>,
18{
19 type Output = I::Output;
20
21 fn index(&self, index: I) -> &Self::Output {
22 let slice = &self.buffer[self.start_offset..];
23 &slice[index]
24 }
25}
26
27impl<I> IndexMut<I> for RawVec
28where
29 I: SliceIndex<[MaybeUninit<u8>]>,
30{
31 fn index_mut(&mut self, index: I) -> &mut Self::Output {
32 let slice = &mut self.buffer[self.start_offset..];
33 &mut slice[index]
34 }
35}
36
37impl RawVec {
38 /// Creates a new `RawVec` with base alignment.
39 ///
40 /// # Examples
41 ///
42 /// ```
43 /// use cel_runtime::RawVec;
44 /// use std::mem::align_of;
45 /// let vec = RawVec::with_base_alignment(align_of::<u32>());
46 /// ```
47 #[must_use]
48 pub fn with_base_alignment(base_alignment: usize) -> Self {
49 RawVec {
50 base_alignment,
51 start_offset: 0,
52 buffer: Vec::new(),
53 }
54 }
55
56 /// Creates a new `RawVec` with base alignment and initial capacity.
57 #[must_use]
58 pub fn with_base_alignment_and_capacity(base_alignment: usize, capacity: usize) -> Self {
59 let mut buffer = Vec::with_capacity(capacity + base_alignment - 1);
60 let ptr_as_index = buffer.as_ptr() as usize;
61 let start_offset = align_index(base_alignment, ptr_as_index) - ptr_as_index;
62 unsafe { buffer.set_len(start_offset) };
63 RawVec {
64 buffer,
65 base_alignment,
66 start_offset,
67 }
68 }
69
70 /// Returns the capacity of the vector in bytes.
71 #[must_use]
72 pub fn capacity(&self) -> usize {
73 self.buffer.capacity() - self.start_offset
74 }
75
76 /// Returns the current length of the vector in bytes.
77 #[must_use]
78 pub fn len(&self) -> usize {
79 self.buffer.len() - self.start_offset
80 }
81
82 /// Returns true if the vector contains no bytes.
83 #[must_use]
84 pub fn is_empty(&self) -> bool {
85 self.len() == 0
86 }
87
88 /// Reserves capacity for at least additional more elements. The collection may reserve more
89 /// space to guarantee amortized constant time growth. After calling reserve, capacity will be
90 /// greater than or equal to `self.len() + additional`. Does nothing if capacity is already
91 /// sufficient.
92 ///
93 /// # Panics
94 ///
95 /// Panics if the new capacity exceeds `isize::MAX bytes`.
96 pub fn reserve(&mut self, addition: usize) {
97 let capacity = self.len() + addition;
98 if capacity > self.capacity() {
99 let mut new_buffer = Self::with_base_alignment_and_capacity(
100 self.base_alignment,
101 max(capacity, self.capacity() * 2),
102 );
103 unsafe {
104 std::ptr::copy_nonoverlapping(self.as_ptr(), new_buffer.as_mut_ptr(), self.len());
105 }
106 *self = new_buffer;
107 }
108 }
109
110 /// Sets the length of the vector.
111 ///
112 /// # Panics
113 ///
114 /// - The length must be less than or equal to the capacity.
115 ///
116 /// # Safety
117 ///
118 /// - The elements at `old_len..new_len` must be initialized.
119 pub unsafe fn set_len(&mut self, len: usize) {
120 assert!(len <= self.capacity());
121 unsafe { self.buffer.set_len(self.start_offset + len) };
122 }
123
124 /// Returns a raw mutable pointer to the vector's buffer, or a dangling raw pointer valid for
125 /// zero sized reads if the vector didn't allocate.
126 ///
127 /// This method guarantees that for the purpose of the aliasing model, this method does not
128 /// materialize a reference to the underlying slice, and thus the returned pointer will remain
129 /// valid when mixed with other calls to [`Self::as_ptr`], [`Self::as_mut_ptr`]. Note
130 /// that calling other methods that materialize references to the slice, or references to
131 /// specific elements you are planning on accessing through this pointer, may still invalidate
132 /// this pointer.
133 ///
134 /// # Safety
135 ///
136 /// The pointer is valid until the vector buffer is reallocated or the vector's lifetime ends.
137 pub unsafe fn as_mut_ptr(&mut self) -> *mut MaybeUninit<u8> {
138 unsafe { self.buffer.as_mut_ptr().add(self.start_offset) }
139 }
140
141 /// Returns a raw pointer to the vector's buffer, or a dangling raw pointer valid for zero sized
142 /// reads if the vector didn't allocate.
143 ///
144 /// The caller must also ensure that the memory the pointer (non-transitively) points to is
145 /// never written to (except inside an `UnsafeCell`) using this pointer or any pointer derived
146 /// from it. If you need to mutate the contents of the slice, use [`Self::as_mut_ptr`].
147 ///
148 /// This method guarantees that for the purpose of the aliasing model, this method does not
149 /// materialize a reference to the underlying slice, and thus the returned pointer will remain
150 /// valid when mixed with other calls to [`Self::as_ptr`], [`Self::as_mut_ptr`]. Note
151 /// that calling other methods that materialize mutable references to the slice, or mutable
152 /// references to specific elements you are planning on accessing through this pointer, as well
153 /// as writing to those elements, may still invalidate this pointer.
154 ///
155 /// # Safety
156 ///
157 /// The pointer is valid until the vector buffer is reallocated or the vector's lifetime ends.
158 #[must_use]
159 pub unsafe fn as_ptr(&self) -> *const MaybeUninit<u8> {
160 unsafe { self.buffer.as_ptr().add(self.start_offset) }
161 }
162
163 /// Shortens the vector, keeping the first `len` elements and dropping
164 /// the rest.
165 ///
166 /// If `len` is greater or equal to the vector's current length, this has
167 /// no effect.
168 pub fn truncate(&mut self, len: usize) {
169 self.buffer.truncate(self.start_offset + len);
170 }
171}
172
173/* Test module */
174#[cfg(test)]
175mod tests {
176 use super::*;
177
178 #[test]
179 fn with_base_alignment() {
180 let vec = RawVec::with_base_alignment(align_of::<u32>());
181 assert_eq!(vec.capacity(), 0);
182 assert_eq!(vec.len(), 0);
183 }
184
185 #[test]
186 fn with_base_alignment_and_capacity() {
187 let vec = RawVec::with_base_alignment_and_capacity(align_of::<u32>(), 10);
188 assert!(vec.capacity() >= 10);
189 assert_eq!(vec.len(), 0);
190 assert_eq!(unsafe { vec.as_ptr() as usize } % align_of::<u32>(), 0);
191 }
192
193 #[test]
194 fn reserve() {
195 let mut vec = RawVec::with_base_alignment(align_of::<u32>());
196 vec.reserve(10);
197 assert!(vec.capacity() >= 10);
198 assert_eq!(vec.len(), 0);
199 assert_eq!(unsafe { vec.as_ptr() as usize } % align_of::<u32>(), 0);
200 }
201
202 #[test]
203 fn set_len() {
204 let mut vec = RawVec::with_base_alignment_and_capacity(align_of::<u32>(), 10);
205 unsafe { vec.set_len(10) };
206 assert_eq!(vec.len(), 10);
207 assert_eq!(unsafe { vec.as_ptr() as usize } % align_of::<u32>(), 0);
208 }
209
210 #[test]
211 fn index() {
212 let mut vec = RawVec::with_base_alignment_and_capacity(align_of::<u32>(), 10);
213 unsafe { vec.set_len(1) };
214 vec[0].write(42);
215 assert_eq!(unsafe { vec[0].assume_init() }, 42);
216 }
217}