ab_io_type/
variable_bytes.rs1use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
2use crate::trivial_type::TrivialType;
3use crate::{DerefWrapper, IoType, IoTypeOptional};
4use core::mem::MaybeUninit;
5use core::ops::{Deref, DerefMut};
6use core::ptr::NonNull;
7use core::{ptr, slice};
8
9#[derive(Debug)]
16#[repr(C)]
17pub struct VariableBytes<const RECOMMENDED_ALLOCATION: u32 = 0> {
18 bytes: NonNull<u8>,
19 size: NonNull<u32>,
20 capacity: u32,
21}
22
23unsafe impl<const RECOMMENDED_ALLOCATION: u32> IoType for VariableBytes<RECOMMENDED_ALLOCATION> {
25 const METADATA: &[u8] = {
26 const fn metadata(recommended_allocation: u32) -> ([u8; MAX_METADATA_CAPACITY], usize) {
27 if recommended_allocation == 0 {
28 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes0 as u8]]);
29 } else if recommended_allocation == 512 {
30 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes512 as u8]]);
31 } else if recommended_allocation == 1024 {
32 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes1024 as u8]]);
33 } else if recommended_allocation == 2028 {
34 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes2028 as u8]]);
35 } else if recommended_allocation == 4096 {
36 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes4096 as u8]]);
37 } else if recommended_allocation == 8192 {
38 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes8192 as u8]]);
39 } else if recommended_allocation == 16384 {
40 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes16384 as u8]]);
41 } else if recommended_allocation == 32768 {
42 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes32768 as u8]]);
43 } else if recommended_allocation == 65536 {
44 return concat_metadata_sources(&[&[IoTypeMetadataKind::VariableBytes65536 as u8]]);
45 } else if recommended_allocation == 131_072 {
46 return concat_metadata_sources(&[
47 &[IoTypeMetadataKind::VariableBytes131072 as u8],
48 ]);
49 } else if recommended_allocation == 262_144 {
50 return concat_metadata_sources(&[
51 &[IoTypeMetadataKind::VariableBytes262144 as u8],
52 ]);
53 } else if recommended_allocation == 524_288 {
54 return concat_metadata_sources(&[
55 &[IoTypeMetadataKind::VariableBytes524288 as u8],
56 ]);
57 } else if recommended_allocation == 1_048_576 {
58 return concat_metadata_sources(&[&[
59 IoTypeMetadataKind::VariableBytes1048576 as u8
60 ]]);
61 }
62
63 let (io_type, size_bytes) = if recommended_allocation < 2u32.pow(8) {
64 (IoTypeMetadataKind::VariableBytes8b, 1)
65 } else if recommended_allocation < 2u32.pow(16) {
66 (IoTypeMetadataKind::VariableBytes16b, 2)
67 } else {
68 (IoTypeMetadataKind::VariableBytes32b, 4)
69 };
70
71 concat_metadata_sources(&[
72 &[io_type as u8],
73 recommended_allocation.to_le_bytes().split_at(size_bytes).0,
74 ])
75 }
76
77 metadata(RECOMMENDED_ALLOCATION)
79 .0
80 .split_at(metadata(RECOMMENDED_ALLOCATION).1)
81 .0
82 };
83
84 type PointerType = u8;
86
87 #[inline(always)]
88 fn size(&self) -> u32 {
89 self.size()
90 }
91
92 #[inline(always)]
93 fn capacity(&self) -> u32 {
94 self.capacity
95 }
96
97 #[inline(always)]
98 #[track_caller]
99 unsafe fn set_size(&mut self, size: u32) {
100 debug_assert!(
101 size <= self.capacity,
102 "`set_size` called with invalid input {size} for capacity {}",
103 self.capacity
104 );
105
106 unsafe {
108 self.size.write(size);
109 }
110 }
111
112 #[inline(always)]
113 #[track_caller]
114 unsafe fn from_ptr<'a>(
115 ptr: &'a NonNull<Self::PointerType>,
116 size: &'a u32,
117 capacity: u32,
118 ) -> impl Deref<Target = Self> + 'a {
119 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
120 debug_assert!(
121 *size <= capacity,
122 "Size {size} must not exceed capacity {capacity}"
123 );
124
125 DerefWrapper(Self {
126 bytes: *ptr,
127 size: NonNull::from_ref(size),
128 capacity,
129 })
130 }
131
132 #[inline(always)]
133 #[track_caller]
134 unsafe fn from_mut_ptr<'a>(
135 ptr: &'a mut NonNull<Self::PointerType>,
136 size: &'a mut u32,
137 capacity: u32,
138 ) -> impl DerefMut<Target = Self> + 'a {
139 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
140 debug_assert!(
141 *size <= capacity,
142 "Size {size} must not exceed capacity {capacity}"
143 );
144
145 DerefWrapper(Self {
146 bytes: *ptr,
147 size: NonNull::from_mut(size),
148 capacity,
149 })
150 }
151
152 #[inline(always)]
153 unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>> {
154 &self.bytes
155 }
156
157 #[inline(always)]
158 unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>> {
159 &mut self.bytes
160 }
161}
162
163impl<const RECOMMENDED_ALLOCATION: u32> IoTypeOptional for VariableBytes<RECOMMENDED_ALLOCATION> {}
164
165impl<const RECOMMENDED_ALLOCATION: u32> VariableBytes<RECOMMENDED_ALLOCATION> {
166 #[inline(always)]
174 #[track_caller]
175 pub const fn from_buffer<'a>(
176 buffer: &'a [<Self as IoType>::PointerType],
177 size: &'a u32,
178 ) -> impl Deref<Target = Self> + 'a {
179 debug_assert!(buffer.len() == *size as usize, "Invalid size");
180 DerefWrapper(Self {
184 bytes: NonNull::new(buffer.as_ptr().cast_mut()).expect("Not null; qed"),
185 size: NonNull::from_ref(size),
186 capacity: *size,
187 })
188 }
189
190 #[inline(always)]
198 #[track_caller]
199 pub fn from_buffer_mut<'a>(
200 buffer: &'a mut [<Self as IoType>::PointerType],
201 size: &'a mut u32,
202 ) -> impl DerefMut<Target = Self> + 'a {
203 debug_assert_eq!(buffer.len(), *size as usize, "Invalid size");
204
205 DerefWrapper(Self {
206 bytes: NonNull::new(buffer.as_mut_ptr()).expect("Not null; qed"),
207 size: NonNull::from_mut(size),
208 capacity: *size,
209 })
210 }
211
212 #[inline(always)]
220 #[track_caller]
221 pub fn from_uninit<'a>(
222 uninit: &'a mut [MaybeUninit<<Self as IoType>::PointerType>],
223 size: &'a mut u32,
224 ) -> impl DerefMut<Target = Self> + 'a {
225 let capacity = uninit.len();
226 debug_assert!(
227 *size as usize <= capacity,
228 "Size {size} must not exceed capacity {capacity}"
229 );
230 let capacity = capacity as u32;
231
232 DerefWrapper(Self {
233 bytes: NonNull::new(uninit.as_mut_ptr().cast_init()).expect("Not null; qed"),
234 size: NonNull::from_mut(size),
235 capacity,
236 })
237 }
238
239 #[inline(always)]
241 pub const fn size(&self) -> u32 {
242 unsafe { self.size.read() }
244 }
245
246 #[inline(always)]
248 pub fn capacity(&self) -> u32 {
249 self.capacity
250 }
251
252 #[inline(always)]
254 pub const fn get_initialized(&self) -> &[u8] {
255 let size = self.size();
256 let ptr = self.bytes.as_ptr();
257 unsafe { slice::from_raw_parts(ptr, size as usize) }
259 }
260
261 #[inline(always)]
263 pub fn get_initialized_mut(&mut self) -> &mut [u8] {
264 let size = self.size();
265 let ptr = self.bytes.as_ptr();
266 unsafe { slice::from_raw_parts_mut(ptr, size as usize) }
268 }
269
270 #[inline(always)]
274 #[must_use = "Operation may fail"]
275 pub fn append(&mut self, bytes: &[u8]) -> bool {
276 let size = self.size();
277 if bytes.len() + size as usize > self.capacity as usize {
278 return false;
279 }
280
281 let Ok(offset) = isize::try_from(size) else {
283 return false;
284 };
285
286 let mut start = unsafe { self.bytes.offset(offset) };
289 unsafe { ptr::copy_nonoverlapping(bytes.as_ptr(), start.as_mut(), bytes.len()) }
294
295 true
296 }
297
298 #[inline(always)]
302 #[must_use = "Operation may fail"]
303 pub fn truncate(&mut self, new_size: u32) -> bool {
304 if new_size > self.size() {
305 return false;
306 }
307
308 unsafe {
310 self.size.write(new_size);
311 }
312
313 true
314 }
315
316 #[inline(always)]
320 #[must_use = "Operation may fail"]
321 pub fn copy_from<T>(&mut self, src: &T) -> bool
322 where
323 T: IoType,
324 {
325 let src_size = src.size();
326 if src_size > self.capacity {
327 return false;
328 }
329
330 unsafe {
333 self.bytes
334 .copy_from_nonoverlapping(src.as_ptr().cast::<u8>(), src_size as usize);
335 self.size.write(src_size);
336 }
337
338 true
339 }
340
341 #[inline(always)]
346 pub fn as_mut_ptr(&mut self) -> &mut NonNull<u8> {
347 &mut self.bytes
348 }
349
350 #[inline(always)]
353 pub fn cast_ref<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
354 &self,
355 ) -> &VariableBytes<DIFFERENT_RECOMMENDED_ALLOCATION> {
356 unsafe {
359 NonNull::from_ref(self)
360 .cast::<VariableBytes<DIFFERENT_RECOMMENDED_ALLOCATION>>()
361 .as_ref()
362 }
363 }
364
365 #[inline(always)]
368 pub fn cast_mut<const DIFFERENT_RECOMMENDED_ALLOCATION: u32>(
369 &mut self,
370 ) -> &mut VariableBytes<DIFFERENT_RECOMMENDED_ALLOCATION> {
371 unsafe {
374 NonNull::from_mut(self)
375 .cast::<VariableBytes<DIFFERENT_RECOMMENDED_ALLOCATION>>()
376 .as_mut()
377 }
378 }
379
380 #[inline(always)]
384 pub fn read_trivial_type<T>(&self) -> Option<T>
385 where
386 T: TrivialType,
387 {
388 if self.size() < T::SIZE {
389 return None;
390 }
391
392 let ptr = self.bytes.cast::<T>();
393
394 let value = unsafe {
397 if ptr.is_aligned() {
398 ptr.read()
399 } else {
400 ptr.read_unaligned()
401 }
402 };
403
404 Some(value)
405 }
406
407 #[inline(always)]
415 #[must_use = "Operation may fail"]
416 pub unsafe fn assume_init(&mut self, size: u32) -> Option<&mut [u8]> {
417 if size > self.capacity {
418 return None;
419 }
420
421 unsafe {
423 self.size.write(size);
424 }
425 Some(self.get_initialized_mut())
426 }
427}