ab_io_type/
trivial_type.rs1use crate::metadata::{IoTypeMetadataKind, MAX_METADATA_CAPACITY, concat_metadata_sources};
2use crate::unaligned::Unaligned;
3use crate::{DerefWrapper, IoType};
4pub use ab_io_type_derive::TrivialType;
5use core::ops::{Deref, DerefMut};
6use core::ptr;
7use core::ptr::NonNull;
8
9const SIZE_OF<T>: usize = size_of::<T>();
10const SUPPORTED_ARRAY<T, const N: usize>: usize = {
12 assert!(
13 u32::MAX as usize >= N,
14 "Number of array elements must be smaller than 2^32"
15 );
16 assert!(
17 u32::MAX as usize >= size_of::<[T; N]>(),
18 "Type size must be smaller than 2^32"
19 );
20 0
21};
22pub(crate) const NON_ZERO_SIZED<T: TrivialType>: usize = {
24 assert!(T::SIZE > 0, "Zero-sized types are not supported");
25 0
26};
27
28pub unsafe trait TrivialType
45where
46 Self: Copy,
47{
48 const SIZE: u32 = {
49 assert!(
50 u32::MAX as usize >= size_of::<Self>(),
51 "Type size must be smaller than 2^32"
52 );
53 size_of::<Self>() as u32
54 };
55 const METADATA: &[u8];
58
59 #[inline(always)]
68 unsafe fn read_unaligned(bytes: &[u8]) -> Option<Self> {
69 Some(unsafe { Unaligned::<Self>::from_bytes(bytes)?.as_inner() })
71 }
72
73 #[inline(always)]
78 unsafe fn read_unaligned_unchecked(bytes: &[u8]) -> Self {
79 unsafe { Unaligned::<Self>::from_bytes_unchecked(bytes).as_inner() }
81 }
82
83 #[inline(always)]
93 unsafe fn from_bytes(bytes: &[u8]) -> Option<&Self> {
94 let (before, slice, _) = unsafe { bytes.align_to::<Self>() };
96
97 before.is_empty().then(|| slice.first()).flatten()
98 }
99
100 #[inline(always)]
105 unsafe fn from_bytes_unchecked(bytes: &[u8]) -> &Self {
106 unsafe { bytes.as_ptr().cast::<Self>().as_ref_unchecked() }
108 }
109
110 #[inline(always)]
120 unsafe fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self> {
121 let (before, slice, _) = unsafe { bytes.align_to_mut::<Self>() };
123
124 before.is_empty().then(|| slice.first_mut()).flatten()
125 }
126
127 #[inline(always)]
132 unsafe fn from_bytes_mut_unchecked(bytes: &mut [u8]) -> &mut Self {
133 unsafe { bytes.as_mut_ptr().cast::<Self>().as_mut_unchecked() }
135 }
136
137 #[inline(always)]
139 fn as_bytes(&self) -> &[u8; SIZE_OF::<Self>] {
140 unsafe { ptr::from_ref(self).cast::<[u8; _]>().as_ref_unchecked() }
142 }
143
144 #[inline(always)]
150 unsafe fn as_bytes_mut(&mut self) -> &mut [u8; SIZE_OF::<Self>] {
151 unsafe { ptr::from_mut(self).cast::<[u8; _]>().as_mut_unchecked() }
153 }
154}
155
156unsafe impl TrivialType for () {
158 const METADATA: &[u8] = &[IoTypeMetadataKind::Unit as u8];
159}
160unsafe impl TrivialType for u8 {
162 const METADATA: &[u8] = &[IoTypeMetadataKind::U8 as u8];
163}
164unsafe impl TrivialType for u16 {
166 const METADATA: &[u8] = &[IoTypeMetadataKind::U16 as u8];
167}
168unsafe impl TrivialType for u32 {
170 const METADATA: &[u8] = &[IoTypeMetadataKind::U32 as u8];
171}
172unsafe impl TrivialType for u64 {
174 const METADATA: &[u8] = &[IoTypeMetadataKind::U64 as u8];
175}
176unsafe impl TrivialType for u128 {
178 const METADATA: &[u8] = &[IoTypeMetadataKind::U128 as u8];
179}
180unsafe impl TrivialType for i8 {
182 const METADATA: &[u8] = &[IoTypeMetadataKind::I8 as u8];
183}
184unsafe impl TrivialType for i16 {
186 const METADATA: &[u8] = &[IoTypeMetadataKind::I16 as u8];
187}
188unsafe impl TrivialType for i32 {
190 const METADATA: &[u8] = &[IoTypeMetadataKind::I32 as u8];
191}
192unsafe impl TrivialType for i64 {
194 const METADATA: &[u8] = &[IoTypeMetadataKind::I64 as u8];
195}
196unsafe impl TrivialType for i128 {
198 const METADATA: &[u8] = &[IoTypeMetadataKind::I128 as u8];
199}
200
201const fn array_metadata(size: u32, inner_metadata: &[u8]) -> ([u8; MAX_METADATA_CAPACITY], usize) {
202 if inner_metadata.len() == 1 && inner_metadata[0] == IoTypeMetadataKind::U8 as u8 {
203 if size == 8 {
204 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x8 as u8]]);
205 } else if size == 16 {
206 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x16 as u8]]);
207 } else if size == 32 {
208 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x32 as u8]]);
209 } else if size == 64 {
210 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x64 as u8]]);
211 } else if size == 128 {
212 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x128 as u8]]);
213 } else if size == 256 {
214 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x256 as u8]]);
215 } else if size == 512 {
216 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x512 as u8]]);
217 } else if size == 1024 {
218 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x1024 as u8]]);
219 } else if size == 2028 {
220 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x2028 as u8]]);
221 } else if size == 4096 {
222 return concat_metadata_sources(&[&[IoTypeMetadataKind::ArrayU8x4096 as u8]]);
223 }
224 }
225
226 let (io_type, size_bytes) = if size < 2u32.pow(8) {
227 (IoTypeMetadataKind::Array8b, 1)
228 } else if size < 2u32.pow(16) {
229 (IoTypeMetadataKind::Array16b, 2)
230 } else {
231 (IoTypeMetadataKind::Array32b, 4)
232 };
233
234 concat_metadata_sources(&[
235 &[io_type as u8],
236 size.to_le_bytes().split_at(size_bytes).0,
237 inner_metadata,
238 ])
239}
240
241unsafe impl<const SIZE: usize, T> TrivialType for [T; SIZE]
245where
246 T: TrivialType,
247 [(); SUPPORTED_ARRAY::<T, SIZE>]:,
248{
249 const METADATA: &[u8] = {
251 array_metadata(SIZE as u32, T::METADATA)
253 .0
254 .split_at(array_metadata(SIZE as u32, T::METADATA).1)
255 .0
256 };
257}
258
259unsafe impl<T> IoType for T
261where
262 T: TrivialType,
263{
264 const METADATA: &[u8] = T::METADATA;
265
266 type PointerType = T;
267
268 #[inline(always)]
269 fn size(&self) -> u32 {
270 T::SIZE
271 }
272
273 #[inline(always)]
274 fn capacity(&self) -> u32 {
275 self.size()
276 }
277
278 #[inline(always)]
279 #[track_caller]
280 unsafe fn set_size(&mut self, size: u32) {
281 debug_assert_eq!(size, T::SIZE, "`set_size` called with invalid input");
282 }
283
284 #[inline(always)]
285 #[track_caller]
286 unsafe fn from_ptr<'a>(
287 ptr: &'a NonNull<Self::PointerType>,
288 size: &'a u32,
289 capacity: u32,
290 ) -> impl Deref<Target = Self> + 'a {
291 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
292 debug_assert_eq!(*size, T::SIZE, "Invalid size");
293 debug_assert!(
294 *size <= capacity,
295 "Size {size} must not exceed capacity {capacity}"
296 );
297
298 unsafe { ptr.as_ref() }
300 }
301
302 #[inline(always)]
303 #[track_caller]
304 unsafe fn from_mut_ptr<'a>(
305 ptr: &'a mut NonNull<Self::PointerType>,
306 _size: &'a mut u32,
307 capacity: u32,
308 ) -> impl DerefMut<Target = Self> + 'a {
309 debug_assert!(ptr.is_aligned(), "Misaligned pointer");
310 debug_assert!(
311 Self::SIZE <= capacity,
312 "Size {} must not exceed capacity {capacity}",
313 Self::SIZE
314 );
315
316 unsafe { ptr.as_mut() }
318 }
319
320 #[inline(always)]
321 unsafe fn as_ptr(&self) -> impl Deref<Target = NonNull<Self::PointerType>> {
322 DerefWrapper(NonNull::from_ref(self))
323 }
324
325 #[inline(always)]
326 unsafe fn as_mut_ptr(&mut self) -> impl DerefMut<Target = NonNull<Self::PointerType>> {
327 DerefWrapper(NonNull::from_mut(self))
328 }
329}