Skip to main content

stack_array/
lib.rs

1//^
2//^ HEAD
3//^
4
5//> HEAD -> NO_STD
6#![no_std]
7
8//> HEAD -> DOC
9#![doc = include_str!("README.md")]
10
11//> HEAD -> LINTS
12#![allow(incomplete_features)]
13
14//> HEAD -> FEATURES
15#![feature(const_cmp)]
16#![feature(const_destruct)]
17#![feature(const_drop_in_place)]
18#![feature(const_array)]
19#![feature(transmute_neo)]
20#![feature(const_index)]
21#![feature(const_range)]
22#![feature(maybe_uninit_uninit_array_transpose)]
23#![feature(const_closures)]
24#![feature(const_trait_impl)]
25#![feature(const_heap)]
26#![feature(trusted_len)]
27#![feature(const_clone)]
28#![feature(new_range)]
29#![feature(const_slice_make_iter)]
30#![feature(generic_const_exprs)]
31#![feature(const_iter)]
32#![feature(const_convert)]
33#![feature(const_default)]
34
35//> HEAD -> CRATES
36extern crate alloc;
37
38//> HEAD -> MODULES
39mod comparisons;
40mod conversions;
41mod errors;
42mod iterators;
43mod references;
44
45//> HEAD -> IMPORTS
46use {
47    core::{
48        fmt::{
49            Debug,
50            Formatter,
51            Result as Format
52        },
53        marker::Destruct,
54        mem::{
55            MaybeUninit,
56            forget,
57            transmute_neo as transmute
58        },
59        ops::{
60            Bound,
61            Drop,
62            RangeBounds
63        },
64        array::from_fn as arrayfn,
65        ptr::{
66            copy,
67            read
68        },
69        hint::unreachable_unchecked,
70        hash::{
71            Hash,
72            Hasher
73        }
74    },
75    constrangeiter::ConstIntoIterator
76};
77
78//> HEAD -> EXPORTS
79pub use errors::{
80    CapacityExceeded,
81    UnmatchedCapacity
82};
83
84
85//^
86//^ ARRAY
87//^
88
89//> ARRAY -> STRUCT
90pub struct Array<Type, const N: usize> {
91    length: usize,
92    data: [MaybeUninit<Type>; N]
93}
94
95//> ARRAY -> IMPLEMENTATION
96impl<Type, const N: usize> Array<Type, N> {
97    pub const fn len(&self) -> usize {return self.length}
98    pub const fn new() -> Self {return Self::default()}
99    pub const fn is_full(&self) -> bool {return self.length == N}
100    pub const fn repeat<const TIMES: usize>(self) -> Array<
101        Type, 
102        {TIMES * N}
103    > where Type: [const] Clone + [const] Destruct, [(); TIMES * N]: {
104        let (length, mut data) = self.into();
105        let mut additional = MaybeUninit::<[Type; TIMES * N]>::uninit().transpose();
106        if TIMES == 0 {for index in (0..length).const_into_iter() {
107            unsafe {data[index].assume_init_drop();};
108        }} else {
109            for index in (0..length).const_into_iter() {
110                additional[index].write(unsafe {data[index].assume_init_read()});
111            }
112            for iteration in (1..TIMES).const_into_iter() {
113                for index in (0..length).const_into_iter() {
114                    additional[index + length * iteration].write(unsafe {
115                        data[index].assume_init_ref().clone()
116                    });
117                }
118            }
119        }
120        return Array::from((length * TIMES, additional));
121    }
122    pub const fn resize<const M: usize>(
123        self
124    ) -> Array<Type, M> where Type: [const] Destruct {
125        let (length, mut data) = self.into();
126        let mut additional = MaybeUninit::<[Type; M]>::uninit().transpose();
127        return if M >= length {
128            for index in (0..length).const_into_iter() {
129                additional[index].write(unsafe {data[index].assume_init_read()});
130            }
131            Array::from((length, additional))
132        } else {
133            for index in (0..M).const_into_iter() {
134                additional[index].write(unsafe {data[index].assume_init_read()});
135            }
136            for index in (M..length).const_into_iter() {
137                unsafe {data[index].assume_init_drop()};
138            }
139            Array::from((M, additional))
140        }
141    }
142    pub const fn divide<const AT: usize>(self) -> (
143        Array<Type, AT>, 
144        Array<Type, {N - AT}>
145    ) where [(); N - AT]: {
146        let (length, data) = self.into();
147        let (first, second) = unsafe {transmute(data)};
148        return (Array {
149            length: length.min(AT),
150            data: first
151        }, Array {
152            length: length.saturating_sub(AT),
153            data: second
154        })
155    }
156    pub const fn join<const M: usize>(self, other: Array<Type, M>) -> Array<Type, {N + M}> {
157        let (length, data) = self.into();
158        let (slength, sdata) = other.into();
159        let mut together = unsafe {transmute::<_, [MaybeUninit<Type>; N + M]>((data, sdata))};
160        let pointer = together.as_mut_ptr();
161        unsafe {copy(
162            pointer.add(N),
163            pointer.add(length),
164            slength
165        )}
166        return Array {
167            length: length + slength,
168            data: together
169        }
170    }
171    #[track_caller]
172    pub const fn push(&mut self, value: Type) -> () {
173        self.push_mut(value);
174    }
175    #[track_caller]
176    pub const fn push_mut<'valid>(&'valid mut self, value: Type) -> &'valid mut Type {
177        let reference = self.data[self.length].write(value);
178        self.length += 1;
179        return reference;
180    }
181    pub const fn pop(&mut self) -> Option<Type> {return self.pop_if(const |_| true)}
182    pub const fn pop_if(
183        &mut self,
184        decider: impl [const] FnOnce(&mut Type) -> bool + [const] Destruct
185    ) -> Option<Type> {return if self.length == 0 {None} else {
186        let last = unsafe {self.data[self.length - 1].assume_init_mut()};
187        if decider(last) {
188            self.length -= 1;
189            Some(unsafe {read(last as *const Type)})
190        } else {
191            None
192        }
193    }}
194    pub const fn clear(&mut self) -> () where Type: [const] Destruct {self.truncate(0)}
195    pub const fn truncate(&mut self, length: usize) -> () where Type: [const] Destruct {
196        for index in (length..self.length).const_into_iter() {
197            unsafe {self.data.get_unchecked_mut(index).assume_init_drop()};
198        }
199        if length < self.length {self.length = length}
200    }
201    #[track_caller]
202    pub const fn insert(&mut self, index: usize, value: Type) -> () {
203        self.insert_mut(index, value);
204    }
205    #[track_caller]
206    pub const fn insert_mut<'valid>(
207        &'valid mut self, 
208        index: usize, 
209        value: Type
210    ) -> &'valid mut Type {
211        assert!(index <= self.length, "tried to insert out of bounds");
212        assert!(self.length != N, "array capacity exceeded");
213        let pointer = unsafe {self.data.as_mut_ptr().add(index)};
214        unsafe {copy(
215            pointer,
216            pointer.add(1),
217            self.length - index
218        )};
219        let reference = unsafe {self.data.get_unchecked_mut(index).write(value)};
220        self.length += 1;
221        return reference;
222    }
223    #[track_caller]
224    pub const fn remove(&mut self, index: usize) -> Type {
225        assert!(index < self.length, "tried to remove out of bounds");
226        let value = unsafe {self.data.get_unchecked(index).assume_init_read()};
227        let pointer = unsafe {self.data.as_mut_ptr().add(index)};
228        unsafe {copy(
229            pointer.add(1),
230            pointer,
231            self.length - index - 1
232        )};
233        self.length -= 1;
234        return value;
235    }
236    #[track_caller]
237    pub const fn swap_remove(&mut self, index: usize) -> Type {
238        assert!(index <= self.length - 1, "tried to remove out of bounds");
239        let value = unsafe {self.data[index].assume_init_read()};
240        self.data.swap(index, self.length - 1);
241        self.length -= 1;
242        return value;
243    }
244    pub const fn retain(
245        &mut self, 
246        mut closure: impl [const] FnMut(&mut Type) -> bool + [const] Destruct
247    ) -> () where Type: [const] Destruct {
248        let mut offset = 0;
249        for index in (0..self.length).const_into_iter() {
250            let mut item = unsafe {self.data[index].assume_init_read()};
251            if closure(&mut item) {
252                if offset == 0 {forget(item)} else {self.data[index - offset].write(item);}
253            } else {
254                drop(item);
255                offset += 1;
256            }
257        }
258        self.length -= offset;
259    }
260    pub const fn dedup(
261        &mut self
262    ) -> () where Type: [const] PartialEq<Type> + [const] Destruct {self.dedup_by_key_with(
263        const |element| element as *const Type,
264        const |first, second| unsafe {first.as_ref_unchecked() == second.as_ref_unchecked()}
265    )}
266    pub const fn dedup_with(
267        &mut self,
268        mut decider: impl [const] FnMut(&mut Type, &mut Type) -> bool + [const] Destruct
269    ) -> () where Type: [const] Destruct {self.dedup_by_key_with(
270        const |element| element as *mut Type, 
271        const |first, second| decider(
272            unsafe {first.as_mut()}.unwrap(), 
273            unsafe {second.as_mut()}.unwrap()
274        )
275    )}
276    pub const fn dedup_by_key<
277        'valid, 
278        Key: 'valid + [const] PartialEq<Key> + [const] Destruct
279    >(
280        &'valid mut self,
281        transformation: impl [const] FnMut(&mut Type) -> Key + [const] Destruct
282    ) -> () where Type: [const] Destruct {self.dedup_by_key_with(
283        transformation, 
284        const |first, second| first == second
285    )}
286    pub const fn dedup_by_key_with<'valid, Key: 'valid + [const] Destruct>(
287        &'valid mut self, 
288        mut transformation: impl [const] FnMut(&mut Type) -> Key + [const] Destruct,
289        mut decider: impl [const] FnMut(&mut Key, &mut Key) -> bool + [const] Destruct
290    ) -> () where Type: [const] Destruct {
291        if self.length == 0 {return}
292        let mut offset = 0;
293        let mut previous = transformation(unsafe {self.data[0].assume_init_mut()});
294        for index in (1..self.length).const_into_iter() {
295            let current = unsafe {self.data[index].assume_init_mut()};
296            let mut key = transformation(current);
297            if decider(&mut previous, &mut key) {
298                drop(key);
299                unsafe {(current as *mut Type).drop_in_place()};
300                offset += 1;
301            } else {
302                previous = key;
303                if offset != 0 {
304                    let value = unsafe {(current as *mut Type).read()};
305                    self.data[index - offset].write(value);
306                }
307            }
308        }
309        self.length -= offset;
310    }
311    pub const fn drain(
312        &mut self, 
313        range: impl [const] RangeBounds<usize> + [const] Destruct
314    ) -> Self {
315        let start = match range.start_bound() {
316            Bound::Excluded(_) => unsafe {unreachable_unchecked()},
317            Bound::Included(bound) => {
318                assert!(*bound < self.length);
319                *bound
320            },
321            Bound::Unbounded => 0
322        };
323        let end = match range.end_bound() {
324            Bound::Excluded(bound) => {
325                assert!(*bound <= self.length);
326                *bound
327            },
328            Bound::Included(bound) => {
329                assert!(*bound < self.length);
330                *bound + 1
331            },
332            Bound::Unbounded => self.length
333        };
334        let mut additional = MaybeUninit::<[Type; N]>::uninit().transpose();
335        let array = match end - start {
336            0 => Array {
337                length: 0,
338                data: additional
339            },
340            1 => {
341                additional[0].write(self.remove(start));
342                Array {
343                    length: 1,
344                    data: additional
345                }
346            },
347            amount => {
348                for index in (start..end).const_into_iter() {
349                    additional[index - start].write(unsafe {
350                        self.data[index].assume_init_read()
351                    });
352                }
353                for index in (end..self.length).const_into_iter() {
354                    self.data[index - end + start].write(unsafe {
355                        self.data[index].assume_init_read()
356                    });
357                }
358                self.length -= end - start;
359                Array {
360                    length: amount,
361                    data: additional
362                }
363            }
364        };
365        return array;
366    }
367}
368
369//> ARRAY -> DROP
370const impl<Type: [const] Destruct, const N: usize> Drop for Array<Type, N> {
371    fn drop(&mut self) {self.clear()}
372}
373
374//> ARRAY -> DEBUG
375impl<Type: Debug, const N: usize> Debug for Array<Type, N> {
376    fn fmt(&self, formatter: &mut Formatter<'_>) -> Format {
377        return self.as_ref().fmt(formatter);
378    }
379}
380
381//> ARRAY -> EXTEND
382impl<Type, const N: usize> Extend<Type> for Array<Type, N> {
383    fn extend<T: IntoIterator<Item = Type>>(&mut self, iter: T) {
384        iter.into_iter().for_each(|item| self.push(item));
385    }
386}
387
388//> ARRAY -> CLONE
389const impl<Type: [const] Clone, const N: usize> Clone for Array<Type, N> {
390    fn clone(&self) -> Self {return Array {
391        length: self.length,
392        data: arrayfn(const |index| if index >= self.length {MaybeUninit::uninit()} else {
393            MaybeUninit::new(unsafe {self.data[index].assume_init_ref()}.clone())
394        })
395    }}
396}
397
398//> ARRAY -> DEFAULT
399const impl<Type, const N: usize> Default for Array<Type, N> {
400    fn default() -> Self {return Self {
401        data: MaybeUninit::uninit().transpose(),
402        length: 0
403    }}
404}
405
406//> ARRAY -> HASH
407impl<Type: Hash, const N: usize> Hash for Array<Type, N> {
408    fn hash<Hashing: Hasher>(&self, state: &mut Hashing) {
409        return Hash::hash(self.as_ref(), state);
410    }
411}