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: Send + Sized + Copy> Send for ConstFixedArray<TSIZE, T> {}
33unsafe impl<const TSIZE: usize, T: Sync + Sized + Copy> Sync for ConstFixedArray<TSIZE, T> {}
34
35unsafe impl<const TSIZE: usize, T: ReprC + Sized + Copy> ReprC for ConstFixedArray<TSIZE, T> {
36 const CHECK: () = const {
37 osom_lib_reprc::hidden::is_reprc::<T>();
38 osom_lib_reprc::hidden::is_reprc::<PhantomData<T>>();
39 osom_lib_reprc::hidden::is_reprc::<Length>();
40 osom_lib_reprc::hidden::is_reprc::<[T; TSIZE]>();
41 };
42}
43
44impl<const TSIZE: usize, T: Sized + Copy> ConstFixedArray<TSIZE, T> {
45 pub const fn new() -> Self {
52 const {
53 assert!(
54 TSIZE <= Length::MAX_LENGTH.as_usize(),
55 "TSIZE cannot exceed Length::MAX_LENGTH"
56 );
57 assert!(TSIZE > 0, "TSIZE cannot be 0");
58 }
59
60 let empty = unsafe { MaybeUninit::<[T; TSIZE]>::zeroed().assume_init() };
61
62 Self {
63 length: Length::ZERO,
64 inner: empty,
65 _phantom: PhantomData,
66 }
67 }
68
69 #[inline(always)]
71 pub const fn length(&self) -> Length {
72 unsafe { core::hint::assert_unchecked(self.length.as_usize() <= TSIZE) };
73 self.length
74 }
75
76 #[inline(always)]
77 pub const fn is_empty(&self) -> bool {
78 self.length.as_u32() == 0
79 }
80
81 #[inline(always)]
84 pub const fn capacity(&self) -> Length {
85 unsafe { Length::new_unchecked(TSIZE as u32) }
86 }
87
88 #[inline(always)]
90 pub const fn as_slice_const(&self) -> &[T] {
91 unsafe {
92 let result = subslice_const(&self.inner, 0..self.length.as_usize());
93 core::hint::assert_unchecked(result.len() <= TSIZE);
94 result
95 }
96 }
97
98 #[inline(always)]
100 pub const fn as_slice_mut_const(&mut self) -> &mut [T] {
101 unsafe {
102 let result = subslice_mut_const(&mut self.inner, 0..self.length.as_usize());
103 core::hint::assert_unchecked(result.len() <= TSIZE);
104 result
105 }
106 }
107
108 #[inline(always)]
114 pub const fn try_push_array_const<const TARRSIZE: usize>(&mut self, arr: [T; TARRSIZE]) -> Result<(), ArrayError> {
115 self.try_push_slice_const(&arr)
116 }
117
118 pub const fn push_array_const<const TARRSIZE: usize>(&mut self, arr: [T; TARRSIZE]) {
124 match self.try_push_array_const(arr) {
125 Ok(()) => (),
126 Err(err) => match err {
127 ArrayError::LengthLimitExceeded => {
128 panic!("Failed to push array due to length limit exceeded");
129 }
130 ArrayError::AllocationError => {
131 panic!("Failed to push array due to allocation error");
132 }
133 },
134 }
135 }
136
137 pub const fn try_push_slice_const(&mut self, slice: &[T]) -> Result<(), ArrayError> {
143 let len = self.length.as_usize();
144 let tsize = slice.len();
145 if len + tsize > TSIZE {
146 return Err(ArrayError::LengthLimitExceeded);
147 }
148
149 unsafe {
150 let dst = subslice_mut_const(&mut self.inner, len..len + tsize);
151 dst.copy_from_slice(slice);
152 self.length = Length::new_unchecked((len + tsize) as u32);
153 }
154 Ok(())
155 }
156
157 #[inline(always)]
163 pub const fn push_slice_const(&mut self, slice: &[T]) {
164 match self.try_push_slice_const(slice) {
165 Ok(()) => (),
166 Err(err) => match err {
167 ArrayError::LengthLimitExceeded => {
168 panic!("Failed to push slice due to length limit exceeded");
169 }
170 ArrayError::AllocationError => {
171 panic!("Failed to push slice due to allocation error");
172 }
173 },
174 }
175 }
176
177 #[inline(always)]
183 pub const fn try_push_const(&mut self, value: T) -> Result<(), ArrayError> {
184 self.try_push_array_const([value])
185 }
186
187 #[inline(always)]
193 pub const fn push_const(&mut self, value: T) {
194 self.push_array_const([value]);
195 }
196
197 pub const fn try_pop_const(&mut self) -> Result<T, ArrayIsEmptyError> {
203 let len = self.length.as_u32();
204 if len == 0 {
205 return Err(ArrayIsEmptyError);
206 }
207
208 let item = unsafe {
209 self.length = Length::new_unchecked(len - 1);
210 (&raw const self.inner).cast::<T>().add((len - 1) as usize).read()
211 };
212 Ok(item)
213 }
214
215 #[inline(always)]
221 #[must_use]
222 pub const fn pop_const(&mut self) -> T {
223 match self.try_pop_const() {
224 Ok(item) => item,
225 Err(ArrayIsEmptyError) => panic!("Failed to pop due to array being empty"),
226 }
227 }
228
229 #[inline(always)]
231 pub const fn clone_const(&self) -> Self {
232 Self {
233 length: self.length,
234 inner: self.inner,
235 _phantom: PhantomData,
236 }
237 }
238
239 #[inline(always)]
246 pub const unsafe fn as_raw_slice_const(&self) -> &[T; TSIZE] {
247 &self.inner
248 }
249
250 #[inline(always)]
257 pub const unsafe fn as_raw_slice_mut_const(&mut self) -> &mut [T; TSIZE] {
258 &mut self.inner
259 }
260
261 #[inline(always)]
264 pub const fn drain(&mut self) {
265 self.length = Length::ZERO;
266 }
267}