light_utils/offset/
copy.rs

1use std::{mem, ptr};
2
3use light_bounded_vec::{
4    BoundedVec, BoundedVecMetadata, CyclicBoundedVec, CyclicBoundedVecMetadata,
5};
6
7/// Creates a copy of value of type `T` based on the provided `bytes` buffer.
8///
9/// # Safety
10///
11/// This is higly unsafe. This function doesn't ensure alignment and
12/// correctness of provided buffer. The responsibility of such checks is on
13/// the caller.
14pub unsafe fn read_value_at<T>(bytes: &[u8], offset: &mut usize) -> T
15where
16    T: Clone,
17{
18    let size = mem::size_of::<T>();
19    let ptr = bytes[*offset..*offset + size].as_ptr() as *const T;
20    *offset += size;
21    ptr::read(ptr)
22}
23
24/// Creates a `BoundedVec` from the sequence of values provided in `bytes` buffer.
25///
26/// # Safety
27///
28/// This is higly unsafe. This function doesn't ensure alignment and
29/// correctness of provided buffer. The responsibility of such checks is on
30/// the caller.
31///
32/// The `T` type needs to be either a primitive or struct consisting of
33/// primitives. It cannot contain any nested heap-backed stucture (like vectors,
34/// slices etc.).
35pub unsafe fn read_bounded_vec_at<T>(
36    bytes: &[u8],
37    offset: &mut usize,
38    metadata: &BoundedVecMetadata,
39) -> BoundedVec<T>
40where
41    T: Clone,
42{
43    let size = mem::size_of::<T>() * metadata.capacity();
44    let ptr = bytes[*offset..*offset + size].as_ptr() as *const T;
45
46    let mut vec = BoundedVec::with_metadata(metadata);
47    let dst_ptr: *mut T = vec.as_mut_ptr();
48
49    for i in 0..metadata.length() {
50        let val = ptr::read(ptr.add(i));
51        // SAFETY: We ensured the bounds.
52        unsafe { ptr::write(dst_ptr.add(i), val) };
53    }
54
55    *offset += size;
56
57    vec
58}
59
60/// Creates a `CyclicBoundedVec` from the sequence of values provided in
61/// `bytes` buffer.
62///
63/// # Safety
64///
65/// This is higly unsafe. This function doesn't ensure alignment and
66/// correctness of provided buffer. The responsibility of such checks is on
67/// the caller.
68pub unsafe fn read_cyclic_bounded_vec_at<T>(
69    bytes: &[u8],
70    offset: &mut usize,
71    metadata: &CyclicBoundedVecMetadata,
72) -> CyclicBoundedVec<T>
73where
74    T: Clone,
75{
76    let size = mem::size_of::<T>() * metadata.capacity();
77    let src_ptr = bytes[*offset..*offset + size].as_ptr() as *const T;
78
79    let mut vec = CyclicBoundedVec::with_metadata(metadata);
80    let dst_ptr: *mut T = vec.as_mut_ptr();
81
82    for i in 0..metadata.length() {
83        let val = ptr::read(src_ptr.add(i));
84        // SAFETY: We ensured the bounds.
85        unsafe { ptr::write(dst_ptr.add(i), val) };
86    }
87
88    *offset += size;
89
90    vec
91}
92
93#[cfg(test)]
94mod test {
95    use std::slice;
96
97    use super::*;
98
99    use bytemuck::{Pod, Zeroable};
100    use memoffset::offset_of;
101
102    #[test]
103    fn test_value_at() {
104        #[derive(Clone, Copy, Pod, Zeroable)]
105        #[repr(C)]
106        struct TestStruct {
107            a: isize,
108            b: usize,
109            c: i64,
110            d: u64,
111            e: i32,
112            f: u32,
113            g: i16,
114            _padding_1: [u8; 2],
115            h: u16,
116            _padding_2: [u8; 2],
117            i: i8,
118            _padding_3: [i8; 3],
119            j: u8,
120            _padding_4: [i8; 3],
121        }
122
123        let mut buf = vec![0_u8; mem::size_of::<TestStruct>()];
124        let s = buf.as_mut_ptr() as *mut TestStruct;
125
126        unsafe {
127            (*s).a = isize::MIN;
128            (*s).b = usize::MAX;
129            (*s).c = i64::MIN;
130            (*s).d = u64::MAX;
131            (*s).e = i32::MIN;
132            (*s).f = u32::MAX;
133            (*s).g = i16::MIN;
134            (*s).h = u16::MAX;
135            (*s).i = i8::MIN;
136            (*s).j = u8::MAX;
137
138            let mut offset = offset_of!(TestStruct, a);
139            assert_eq!(offset, 0);
140            assert_eq!(read_value_at::<isize>(&buf, &mut offset), isize::MIN);
141            assert_eq!(offset, 8);
142
143            let mut offset = offset_of!(TestStruct, b);
144            assert_eq!(offset, 8);
145            assert_eq!(read_value_at::<usize>(&buf, &mut offset), usize::MAX);
146            assert_eq!(offset, 16);
147
148            let mut offset = offset_of!(TestStruct, c);
149            assert_eq!(offset, 16);
150            assert_eq!(read_value_at::<i64>(&buf, &mut offset), i64::MIN);
151            assert_eq!(offset, 24);
152
153            let mut offset = offset_of!(TestStruct, d);
154            assert_eq!(offset, 24);
155            assert_eq!(read_value_at::<u64>(&buf, &mut offset), u64::MAX);
156            assert_eq!(offset, 32);
157
158            let mut offset = offset_of!(TestStruct, e);
159            assert_eq!(offset, 32);
160            assert_eq!(read_value_at::<i32>(&buf, &mut offset), i32::MIN);
161            assert_eq!(offset, 36);
162
163            let mut offset = offset_of!(TestStruct, f);
164            assert_eq!(offset, 36);
165            assert_eq!(read_value_at::<u32>(&buf, &mut offset), u32::MAX);
166            assert_eq!(offset, 40);
167
168            let mut offset = offset_of!(TestStruct, g);
169            assert_eq!(offset, 40);
170            assert_eq!(read_value_at::<i16>(&buf, &mut offset), i16::MIN);
171            assert_eq!(offset, 42);
172
173            let mut offset = offset_of!(TestStruct, h);
174            assert_eq!(offset, 44);
175            assert_eq!(read_value_at::<u16>(&buf, &mut offset), u16::MAX);
176            assert_eq!(offset, 46);
177
178            let mut offset = offset_of!(TestStruct, i);
179            assert_eq!(offset, 48);
180            assert_eq!(read_value_at::<i8>(&buf, &mut offset), i8::MIN);
181            assert_eq!(offset, 49);
182
183            let mut offset = offset_of!(TestStruct, j);
184            assert_eq!(offset, 52);
185            assert_eq!(read_value_at::<u8>(&buf, &mut offset), u8::MAX);
186            assert_eq!(offset, 53);
187        }
188    }
189
190    #[test]
191    fn test_read_bounded_vec_at() {
192        #[derive(Clone, Copy, Pod, Zeroable)]
193        #[repr(C)]
194        struct TestStruct {
195            a: [i64; 32],
196            b: [u64; 32],
197            c: [[u8; 32]; 32],
198        }
199
200        let mut buf = vec![0_u8; mem::size_of::<TestStruct>()];
201        let s = buf.as_mut_ptr() as *mut TestStruct;
202
203        unsafe {
204            for (i, element) in (*s).a.iter_mut().enumerate() {
205                *element = -(i as i64);
206            }
207            for (i, element) in (*s).b.iter_mut().enumerate() {
208                *element = i as u64;
209            }
210            for (i, element) in (*s).c.iter_mut().enumerate() {
211                *element = [i as u8; 32];
212            }
213
214            let metadata = BoundedVecMetadata::new_with_length(32, 32);
215            let mut offset = offset_of!(TestStruct, a);
216            assert_eq!(offset, 0);
217            let vec: BoundedVec<i64> = read_bounded_vec_at(&buf, &mut offset, &metadata);
218            for (i, element) in vec.iter().enumerate() {
219                assert_eq!(i as i64, -(*element as i64));
220            }
221            assert_eq!(offset, 256);
222
223            let metadata = BoundedVecMetadata::new_with_length(32, 32);
224            let mut offset = offset_of!(TestStruct, b);
225            assert_eq!(offset, 256);
226            let vec: BoundedVec<u64> = read_bounded_vec_at(&buf, &mut offset, &metadata);
227            for (i, element) in vec.iter().enumerate() {
228                assert_eq!(i as u64, *element as u64);
229            }
230            assert_eq!(offset, 512);
231
232            let metadata = BoundedVecMetadata::new_with_length(32, 32);
233            let mut offset = offset_of!(TestStruct, c);
234            assert_eq!(offset, 512);
235            let vec: BoundedVec<[u8; 32]> = read_bounded_vec_at(&buf, &mut offset, &metadata);
236            for (i, element) in vec.iter().enumerate() {
237                assert_eq!(&[i as u8; 32], element);
238            }
239            assert_eq!(offset, 1536);
240        }
241    }
242
243    #[test]
244    fn test_read_cyclic_bounded_vec_at() {
245        #[derive(Clone, Copy, Pod, Zeroable)]
246        #[repr(C)]
247        struct TestStruct {
248            a: [i64; 32],
249            b: [u64; 32],
250            c: [[u8; 32]; 32],
251        }
252
253        let mut buf = vec![0_u8; mem::size_of::<TestStruct>()];
254        let s = buf.as_mut_ptr() as *mut TestStruct;
255
256        unsafe {
257            for (i, element) in (*s).a.iter_mut().enumerate() {
258                *element = -(i as i64);
259            }
260            for (i, element) in (*s).b.iter_mut().enumerate() {
261                *element = i as u64;
262            }
263            for (i, element) in (*s).c.iter_mut().enumerate() {
264                *element = [i as u8; 32];
265            }
266
267            // Start the cyclic vecs from the middle.
268
269            let metadata = CyclicBoundedVecMetadata::new_with_indices(32, 32, 14, 13);
270            let mut offset = offset_of!(TestStruct, a);
271            assert_eq!(offset, 0);
272            let vec: CyclicBoundedVec<i64> =
273                read_cyclic_bounded_vec_at(&buf, &mut offset, &metadata);
274            assert_eq!(vec.capacity(), 32);
275            assert_eq!(vec.len(), 32);
276            assert_eq!(vec.first_index(), 14);
277            assert_eq!(vec.last_index(), 13);
278            assert_eq!(
279                vec.iter().collect::<Vec<_>>().as_slice(),
280                &[
281                    &-14, &-15, &-16, &-17, &-18, &-19, &-20, &-21, &-22, &-23, &-24, &-25, &-26,
282                    &-27, &-28, &-29, &-30, &-31, &-0, &-1, &-2, &-3, &-4, &-5, &-6, &-7, &-8, &-9,
283                    &-10, &-11, &-12, &-13
284                ]
285            );
286            assert_eq!(offset, 256);
287
288            let metadata = CyclicBoundedVecMetadata::new_with_indices(32, 32, 14, 13);
289            let mut offset = offset_of!(TestStruct, b);
290            assert_eq!(offset, 256);
291            let vec: CyclicBoundedVec<u64> =
292                read_cyclic_bounded_vec_at(&buf, &mut offset, &metadata);
293            assert_eq!(vec.capacity(), 32);
294            assert_eq!(vec.len(), 32);
295            assert_eq!(vec.first_index(), 14);
296            assert_eq!(vec.last_index(), 13);
297            assert_eq!(
298                vec.iter().collect::<Vec<_>>().as_slice(),
299                &[
300                    &14, &15, &16, &17, &18, &19, &20, &21, &22, &23, &24, &25, &26, &27, &28, &29,
301                    &30, &31, &0, &1, &2, &3, &4, &5, &6, &7, &8, &9, &10, &11, &12, &13
302                ]
303            );
304            assert_eq!(offset, 512);
305
306            let metadata = CyclicBoundedVecMetadata::new_with_indices(32, 32, 14, 13);
307            let mut offset = offset_of!(TestStruct, c);
308            assert_eq!(offset, 512);
309            let vec: CyclicBoundedVec<[u8; 32]> =
310                read_cyclic_bounded_vec_at(&buf, &mut offset, &metadata);
311            assert_eq!(vec.capacity(), 32);
312            assert_eq!(vec.len(), 32);
313            assert_eq!(vec.first_index(), 14);
314            assert_eq!(vec.last_index(), 13);
315            assert_eq!(
316                vec.iter().collect::<Vec<_>>().as_slice(),
317                &[
318                    &[14_u8; 32],
319                    &[15_u8; 32],
320                    &[16_u8; 32],
321                    &[17_u8; 32],
322                    &[18_u8; 32],
323                    &[19_u8; 32],
324                    &[20_u8; 32],
325                    &[21_u8; 32],
326                    &[22_u8; 32],
327                    &[23_u8; 32],
328                    &[24_u8; 32],
329                    &[25_u8; 32],
330                    &[26_u8; 32],
331                    &[27_u8; 32],
332                    &[28_u8; 32],
333                    &[29_u8; 32],
334                    &[30_u8; 32],
335                    &[31_u8; 32],
336                    &[0_u8; 32],
337                    &[1_u8; 32],
338                    &[2_u8; 32],
339                    &[3_u8; 32],
340                    &[4_u8; 32],
341                    &[5_u8; 32],
342                    &[6_u8; 32],
343                    &[7_u8; 32],
344                    &[8_u8; 32],
345                    &[9_u8; 32],
346                    &[10_u8; 32],
347                    &[11_u8; 32],
348                    &[12_u8; 32],
349                    &[13_u8; 32],
350                ]
351            );
352            assert_eq!(offset, 1536);
353        }
354    }
355
356    #[test]
357    fn test_read_cyclic_bounded_vec_first_last() {
358        let mut vec = CyclicBoundedVec::<u32>::with_capacity(2);
359        vec.push(0);
360        vec.push(37);
361        vec.push(49);
362
363        let metadata_bytes = vec.metadata().to_le_bytes();
364        let metadata = CyclicBoundedVecMetadata::from_le_bytes(metadata_bytes);
365        let bytes = unsafe {
366            slice::from_raw_parts(
367                vec.as_mut_ptr() as *mut u8,
368                mem::size_of::<u32>() * vec.capacity(),
369            )
370        };
371
372        let mut offset = 0;
373        let vec_copy: CyclicBoundedVec<u32> =
374            unsafe { read_cyclic_bounded_vec_at(bytes, &mut offset, &metadata) };
375
376        assert_eq!(*vec.first().unwrap(), 37);
377        assert_eq!(vec.first(), vec_copy.first()); // Fails. Both should be 37
378        assert_eq!(*vec.last().unwrap(), 49);
379        assert_eq!(vec.last(), vec_copy.last()); // Fails. Both should be 49
380    }
381}