osom_lib_arrays/fixed_array/
const_fixed_array.rs1#![allow(clippy::cast_possible_truncation, clippy::new_without_default)]
2
3use core::{marker::PhantomData, mem::MaybeUninit};
4
5use osom_lib_primitives::length::Length;
6use osom_lib_reprc::traits::ReprC;
7
8use crate::{
9 const_helpers::{subslice_const, subslice_mut_const},
10 errors::{ArrayError, ArrayIsEmptyError},
11};
12
13#[repr(C)]
25#[must_use]
26pub struct ConstFixedArray<const TSIZE: usize, T: Sized + Copy> {
27 length: Length,
28 inner: [T; TSIZE],
29 _phantom: PhantomData<T>,
30}
31
32unsafe impl<const TSIZE: usize, T: ReprC + Sized + Copy> ReprC for ConstFixedArray<TSIZE, T> {
33 const CHECK: () = {
34 let () = T::CHECK;
35 let () = <PhantomData<T> as ReprC>::CHECK;
36 let () = <Length as ReprC>::CHECK;
37 let () = <[T; TSIZE] as ReprC>::CHECK;
38 };
39}
40
41impl<const TSIZE: usize, T: Sized + Copy> ConstFixedArray<TSIZE, T> {
42 pub const fn new() -> Self {
49 const {
50 assert!(
51 TSIZE <= Length::MAX_LENGTH.as_usize(),
52 "TSIZE cannot exceed Length::MAX_LENGTH"
53 );
54 assert!(TSIZE > 0, "TSIZE cannot be 0");
55 }
56
57 let empty = unsafe { MaybeUninit::<[T; TSIZE]>::zeroed().assume_init() };
58
59 Self {
60 length: Length::ZERO,
61 inner: empty,
62 _phantom: PhantomData,
63 }
64 }
65
66 #[inline(always)]
68 pub const fn length(&self) -> Length {
69 unsafe { core::hint::assert_unchecked(self.length.as_usize() <= TSIZE) };
70 self.length
71 }
72
73 #[inline(always)]
74 pub const fn is_empty(&self) -> bool {
75 self.length.as_u32() == 0
76 }
77
78 #[inline(always)]
81 pub const fn capacity(&self) -> Length {
82 unsafe { Length::new_unchecked(TSIZE as u32) }
83 }
84
85 #[inline(always)]
87 pub const fn as_slice_const(&self) -> &[T] {
88 unsafe {
89 let result = subslice_const(&self.inner, 0..self.length.as_usize());
90 core::hint::assert_unchecked(result.len() <= TSIZE);
91 result
92 }
93 }
94
95 #[inline(always)]
97 pub const fn as_slice_mut_const(&mut self) -> &mut [T] {
98 unsafe {
99 let result = subslice_mut_const(&mut self.inner, 0..self.length.as_usize());
100 core::hint::assert_unchecked(result.len() <= TSIZE);
101 result
102 }
103 }
104
105 #[inline(always)]
111 pub const fn try_push_array_const<const TARRSIZE: usize>(&mut self, arr: [T; TARRSIZE]) -> Result<(), ArrayError> {
112 self.try_push_slice_const(&arr)
113 }
114
115 pub const fn push_array_const<const TARRSIZE: usize>(&mut self, arr: [T; TARRSIZE]) {
121 match self.try_push_array_const(arr) {
122 Ok(()) => (),
123 Err(err) => match err {
124 ArrayError::LengthLimitExceeded => {
125 panic!("Failed to push array due to length limit exceeded");
126 }
127 ArrayError::AllocationError => {
128 panic!("Failed to push array due to allocation error");
129 }
130 },
131 }
132 }
133
134 pub const fn try_push_slice_const(&mut self, slice: &[T]) -> Result<(), ArrayError> {
140 let len = self.length.as_usize();
141 let tsize = slice.len();
142 if len + tsize > TSIZE {
143 return Err(ArrayError::LengthLimitExceeded);
144 }
145
146 unsafe {
147 let dst = subslice_mut_const(&mut self.inner, len..len + tsize);
148 dst.copy_from_slice(slice);
149 self.length = Length::new_unchecked((len + tsize) as u32);
150 }
151 Ok(())
152 }
153
154 #[inline(always)]
160 pub const fn push_slice_const(&mut self, slice: &[T]) {
161 match self.try_push_slice_const(slice) {
162 Ok(()) => (),
163 Err(err) => match err {
164 ArrayError::LengthLimitExceeded => {
165 panic!("Failed to push slice due to length limit exceeded");
166 }
167 ArrayError::AllocationError => {
168 panic!("Failed to push slice due to allocation error");
169 }
170 },
171 }
172 }
173
174 #[inline(always)]
180 pub const fn try_push_const(&mut self, value: T) -> Result<(), ArrayError> {
181 self.try_push_array_const([value])
182 }
183
184 #[inline(always)]
190 pub const fn push_const(&mut self, value: T) {
191 self.push_array_const([value]);
192 }
193
194 pub const fn try_pop_const(&mut self) -> Result<T, ArrayIsEmptyError> {
200 let len = self.length.as_u32();
201 if len == 0 {
202 return Err(ArrayIsEmptyError);
203 }
204
205 let item = unsafe {
206 self.length = Length::new_unchecked(len - 1);
207 (&raw const self.inner).cast::<T>().add((len - 1) as usize).read()
208 };
209 Ok(item)
210 }
211
212 #[inline(always)]
218 #[must_use]
219 pub const fn pop_const(&mut self) -> T {
220 match self.try_pop_const() {
221 Ok(item) => item,
222 Err(ArrayIsEmptyError) => panic!("Failed to pop due to array being empty"),
223 }
224 }
225
226 #[inline(always)]
228 pub const fn clone_const(&self) -> Self {
229 Self {
230 length: self.length,
231 inner: self.inner,
232 _phantom: PhantomData,
233 }
234 }
235
236 #[inline(always)]
243 pub const unsafe fn as_raw_slice_const(&self) -> &[T; TSIZE] {
244 &self.inner
245 }
246
247 #[inline(always)]
254 pub const unsafe fn as_raw_slice_mut_const(&mut self) -> &mut [T; TSIZE] {
255 &mut self.inner
256 }
257
258 #[inline(always)]
261 pub const fn drain(&mut self) {
262 self.length = Length::ZERO;
263 }
264}