osom_lib_arrays/fixed_array/
inline_fixed_array.rs1#![allow(clippy::cast_possible_truncation)]
2
3use core::{
4 borrow::{Borrow, BorrowMut},
5 hash::Hash,
6 marker::PhantomData,
7 mem::{ManuallyDrop, MaybeUninit},
8};
9
10use osom_lib_primitives::length::Length;
11use osom_lib_reprc::traits::ReprC;
12use osom_lib_try_clone::TryClone;
13
14use crate::{
15 errors::{ArrayError, ArrayIsEmptyError, ArrayTryCloneError},
16 traits::{ImmutableArray, MutableArray},
17};
18
19#[repr(C)]
25#[derive(Debug)]
26#[must_use]
27pub struct InlineFixedArray<const TSIZE: usize, T: Sized> {
28 length: Length,
29 inner: MaybeUninit<[T; TSIZE]>,
30 _phantom: PhantomData<T>,
31}
32
33unsafe impl<const TSIZE: usize, T: Send + Sized> Send for InlineFixedArray<TSIZE, T> {}
34unsafe impl<const TSIZE: usize, T: Sync + Sized> Sync for InlineFixedArray<TSIZE, T> {}
35
36unsafe impl<const TSIZE: usize, T: ReprC + Sized> ReprC for InlineFixedArray<TSIZE, T> {
37 const CHECK: () = const {
38 osom_lib_reprc::hidden::is_reprc::<T>();
39 osom_lib_reprc::hidden::is_reprc::<PhantomData<T>>();
40 osom_lib_reprc::hidden::is_reprc::<Length>();
41 osom_lib_reprc::hidden::is_reprc::<MaybeUninit<[T; TSIZE]>>();
42 };
43}
44
45impl<const TSIZE: usize, T: Sized> InlineFixedArray<TSIZE, T> {
46 pub const fn new() -> Self {
53 const {
54 assert!(
55 TSIZE <= Length::MAX_LENGTH.as_usize(),
56 "TSIZE cannot exceed Length::MAX_LENGTH"
57 );
58 assert!(TSIZE > 0, "TSIZE cannot be 0");
59 }
60
61 Self {
62 length: Length::ZERO,
63 inner: MaybeUninit::uninit(),
64 _phantom: PhantomData,
65 }
66 }
67
68 #[inline(always)]
70 pub const fn length(&self) -> Length {
71 self.length
72 }
73
74 #[inline(always)]
75 pub const fn is_empty(&self) -> bool {
76 self.length.as_u32() == 0
77 }
78
79 #[inline(always)]
82 pub const fn capacity(&self) -> Length {
83 unsafe { Length::new_unchecked(TSIZE as u32) }
84 }
85
86 #[inline(always)]
88 pub const fn as_slice_const(&self) -> &[T] {
89 const {
93 assert!(
94 size_of::<[T; TSIZE]>() == size_of::<ManuallyDrop<[T; TSIZE]>>(),
95 "T and ManuallyDrop<[T; TSIZE]> must have the same size"
96 );
97 assert!(
98 align_of::<[T; TSIZE]>() == align_of::<ManuallyDrop<[T; TSIZE]>>(),
99 "T and ManuallyDrop<[T; TSIZE]> must have the same alignment"
100 );
101 }
102 let ptr = (&raw const self.inner).cast();
103 unsafe { core::slice::from_raw_parts(ptr, self.length.as_usize()) }
104 }
105
106 #[inline(always)]
108 pub const fn as_slice_mut_const(&mut self) -> &mut [T] {
109 const {
113 assert!(
114 size_of::<[T; TSIZE]>() == size_of::<ManuallyDrop<[T; TSIZE]>>(),
115 "T and ManuallyDrop<[T; TSIZE]> must have the same size"
116 );
117 assert!(
118 align_of::<[T; TSIZE]>() == align_of::<ManuallyDrop<[T; TSIZE]>>(),
119 "T and ManuallyDrop<[T; TSIZE]> must have the same alignment"
120 );
121 }
122 let ptr = (&raw mut self.inner).cast();
123 unsafe { core::slice::from_raw_parts_mut(ptr, self.length.as_usize()) }
124 }
125}
126
127impl<const TSIZE: usize, T: Sized> Default for InlineFixedArray<TSIZE, T> {
128 fn default() -> Self {
129 Self::new()
130 }
131}
132
133impl<const TSIZE: usize, T: Sized> ImmutableArray<T> for InlineFixedArray<TSIZE, T> {
134 #[inline(always)]
135 fn length(&self) -> Length {
136 self.length()
137 }
138
139 #[inline(always)]
140 fn capacity(&self) -> Length {
141 self.capacity()
142 }
143}
144
145impl<const TSIZE: usize, T: Sized> MutableArray<T> for InlineFixedArray<TSIZE, T> {
146 fn try_push_array<const TARRSIZE: usize>(&mut self, arr: [T; TARRSIZE]) -> Result<(), ArrayError> {
147 let len = self.length.as_usize();
148 if len + TARRSIZE > TSIZE {
149 return Err(ArrayError::LengthLimitExceeded);
150 }
151
152 unsafe {
153 let mut dst = self.inner.as_mut_ptr().cast::<T>().add(len);
154 let mut src = arr.as_ptr();
155 let end = src.add(TARRSIZE);
156 while src < end {
157 dst.write(src.read());
158 dst = dst.add(1);
159 src = src.add(1);
160 }
161 core::mem::forget(arr);
162 self.length = Length::new_unchecked((len + TARRSIZE) as u32);
163 }
164 Ok(())
165 }
166
167 fn try_push_slice(&mut self, slice: &[T]) -> Result<(), ArrayTryCloneError>
168 where
169 T: TryClone,
170 {
171 let len = self.length.as_usize();
172 let tsize = slice.len();
173 if len + tsize > TSIZE {
174 return Err(ArrayError::LengthLimitExceeded.into());
175 }
176
177 unsafe {
178 let mut dst = self.inner.as_mut_ptr().cast::<T>().add(len);
179 for item in slice {
180 let clone = item.try_clone().map_err(|_| ArrayTryCloneError::ItemCloningError)?;
181 dst.write(clone);
182 dst = dst.add(1);
183 }
184 self.length = Length::new_unchecked((len + tsize) as u32);
185 }
186 Ok(())
187 }
188
189 fn try_pop(&mut self) -> Result<T, ArrayIsEmptyError> {
190 if self.length == Length::ZERO {
191 return Err(ArrayIsEmptyError);
192 }
193
194 let len = self.length.as_u32();
195 let item = unsafe {
196 self.length = Length::new_unchecked(len - 1);
197 self.inner.as_ptr().cast::<T>().add((len - 1) as usize).read()
198 };
199 Ok(item)
200 }
201}
202
203impl<const TSIZE: usize, T: Sized + TryClone> Clone for InlineFixedArray<TSIZE, T> {
204 fn clone(&self) -> Self {
205 self.try_clone().expect("Failed to clone inline fixed array")
206 }
207}
208
209impl<const TSIZE: usize, T: Sized + TryClone> TryClone for InlineFixedArray<TSIZE, T> {
210 type Error = ArrayTryCloneError;
211
212 fn try_clone(&self) -> Result<Self, Self::Error> {
213 let mut new_instance = Self::new();
214 new_instance.try_push_slice(self.as_slice_const())?;
215 Ok(new_instance)
216 }
217}
218
219impl<const TSIZE: usize, T: Sized + PartialEq, Rhs: AsRef<[T]>> PartialEq<Rhs> for InlineFixedArray<TSIZE, T> {
220 fn eq(&self, other: &Rhs) -> bool {
221 self.as_slice_const() == other.as_ref()
222 }
223}
224
225impl<const TSIZE: usize, T: Sized + Eq> Eq for InlineFixedArray<TSIZE, T> {}
226
227impl<const TSIZE: usize, T: Sized + Hash> Hash for InlineFixedArray<TSIZE, T> {
228 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
229 self.as_slice_const().hash(state);
230 }
231}
232
233impl<const TSIZE: usize, T: Sized> AsRef<[T]> for InlineFixedArray<TSIZE, T> {
234 fn as_ref(&self) -> &[T] {
235 self.as_slice_const()
236 }
237}
238
239impl<const TSIZE: usize, T: Sized> AsMut<[T]> for InlineFixedArray<TSIZE, T> {
240 fn as_mut(&mut self) -> &mut [T] {
241 self.as_slice_mut_const()
242 }
243}
244
245impl<const TSIZE: usize, T: Sized> Borrow<[T]> for InlineFixedArray<TSIZE, T> {
246 fn borrow(&self) -> &[T] {
247 self.as_slice_const()
248 }
249}
250
251impl<const TSIZE: usize, T: Sized> BorrowMut<[T]> for InlineFixedArray<TSIZE, T> {
252 fn borrow_mut(&mut self) -> &mut [T] {
253 self.as_slice_mut_const()
254 }
255}
256
257impl<const TSIZE: usize, T: Sized> Drop for InlineFixedArray<TSIZE, T> {
258 fn drop(&mut self) {
259 if !core::mem::needs_drop::<T>() {
260 return;
261 }
262
263 unsafe {
264 let mut start = (&raw mut self.inner).cast::<T>();
265 let end = start.add(self.length.as_usize());
266 while start < end {
267 core::ptr::drop_in_place(start);
268 start = start.add(1);
269 }
270 }
271 }
272}