Skip to main content

standard_lib/collections/circular/stack/
circ_stack.rs

1use std::{array::TryFromSliceError, mem::{self, MaybeUninit}, ops::{Index, IndexMut}};
2
3use super::{Iter, IterMut};
4
5const MAX_SIZE: usize = isize::MAX as usize;
6
7const fn check_size(n: usize) {
8    if !(n <= MAX_SIZE) {
    { ::core::panicking::panic_fmt(format_args!("N exceeds maximum size!")); }
};assert!(n <= MAX_SIZE, "N exceeds maximum size!");
9}
10
11#[derive(#[automatically_derived]
impl<T: ::core::fmt::Debug, const N : usize> ::core::fmt::Debug for
    CircStack<T, N> {
    #[inline]
    fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
        ::core::fmt::Formatter::debug_struct_field2_finish(f, "CircStack",
            "buffer", &self.buffer, "tail", &&self.tail)
    }
}Debug, #[automatically_derived]
impl<T: ::core::clone::Clone, const N : usize> ::core::clone::Clone for
    CircStack<T, N> {
    #[inline]
    fn clone(&self) -> CircStack<T, N> {
        CircStack {
            buffer: ::core::clone::Clone::clone(&self.buffer),
            tail: ::core::clone::Clone::clone(&self.tail),
        }
    }
}Clone, #[automatically_derived]
impl<T: ::core::hash::Hash, const N : usize> ::core::hash::Hash for
    CircStack<T, N> {
    #[inline]
    fn hash<__H: ::core::hash::Hasher>(&self, state: &mut __H) {
        ::core::hash::Hash::hash(&self.buffer, state);
        ::core::hash::Hash::hash(&self.tail, state)
    }
}Hash, #[automatically_derived]
impl<T: ::core::cmp::PartialEq, const N : usize> ::core::cmp::PartialEq for
    CircStack<T, N> {
    #[inline]
    fn eq(&self, other: &CircStack<T, N>) -> bool {
        self.buffer == other.buffer && self.tail == other.tail
    }
}PartialEq, #[automatically_derived]
impl<T: ::core::cmp::Eq, const N : usize> ::core::cmp::Eq for CircStack<T, N>
    {
    #[inline]
    #[doc(hidden)]
    #[coverage(off)]
    fn assert_fields_are_eq(&self) {
        let _: ::core::cmp::AssertParamIsEq<[T; N]>;
        let _: ::core::cmp::AssertParamIsEq<usize>;
    }
}Eq, #[automatically_derived]
impl<T: ::core::cmp::PartialOrd, const N : usize> ::core::cmp::PartialOrd for
    CircStack<T, N> {
    #[inline]
    fn partial_cmp(&self, other: &CircStack<T, N>)
        -> ::core::option::Option<::core::cmp::Ordering> {
        match ::core::cmp::PartialOrd::partial_cmp(&self.buffer,
                &other.buffer) {
            ::core::option::Option::Some(::core::cmp::Ordering::Equal) =>
                ::core::cmp::PartialOrd::partial_cmp(&self.tail, &other.tail),
            cmp => cmp,
        }
    }
}PartialOrd, #[automatically_derived]
impl<T: ::core::cmp::Ord, const N : usize> ::core::cmp::Ord for
    CircStack<T, N> {
    #[inline]
    fn cmp(&self, other: &CircStack<T, N>) -> ::core::cmp::Ordering {
        match ::core::cmp::Ord::cmp(&self.buffer, &other.buffer) {
            ::core::cmp::Ordering::Equal =>
                ::core::cmp::Ord::cmp(&self.tail, &other.tail),
            cmp => cmp,
        }
    }
}Ord)]
12pub struct CircStack<T, const N: usize> {
13    pub(crate) buffer: [T; N],
14    pub(crate) tail: usize,
15}
16
17pub(crate) const fn increment<const N: usize>(index: usize) -> usize {
18    // index + 1 <= MAX_SIZE because index < N <= MAX_SIZE. Can't overflow.
19    (index + 1) % N
20}
21
22pub(crate) const fn sub_wrapping<const N: usize>(index: usize, diff: usize) -> usize {
23    if index >= N {
24        { ::core::panicking::panic_fmt(format_args!("TODO")); }panic!("TODO")
25    }
26
27    unsafe {
28        // SAFETY: index < N <= isize::MAX implies that self.index - index can't be less than
29        // -isize::MAX, which is greater than isize::MIN.
30        index.checked_signed_diff(diff).unwrap_unchecked()
31    }.rem_euclid(N as isize) as usize
32}
33
34impl<T, const N: usize> CircStack<T, N> {
35    pub(crate) const fn increment(&mut self) {
36        self.tail = increment::<N>(self.tail)
37    }
38
39    pub(crate) const fn decrement(&mut self) {
40        self.tail = sub_wrapping::<N>(self.tail, 1);
41    }
42
43    pub(crate) const fn translate_index(&self, index: usize) -> usize {
44        sub_wrapping::<N>(self.tail, index)
45    }
46
47    pub const fn new(buffer: [T; N], tail: usize) -> CircStack<T, N> {
48        const { check_size(N) };
49
50        CircStack {
51            buffer,
52            tail
53        }
54    }
55
56    pub const fn new_uninit() -> CircStack<MaybeUninit<T>, N> {
57        CircStack::new(
58            [const { MaybeUninit::uninit() }; N],
59            0
60        )
61    }
62
63    pub fn push(&mut self, value: T) {
64        self.increment();
65        self.buffer[self.tail] = value;
66    }
67
68    pub const fn pop_with_replacement(&mut self, replacement: T) -> T {
69        let value = mem::replace(&mut self.buffer[self.tail], replacement);
70        self.decrement();
71        value
72    }
73
74    pub const fn as_array(&self) -> &[T; N] {
75        &self.buffer
76    }
77
78    pub const fn as_array_mut(&mut self) -> &mut [T; N] {
79        &mut self.buffer
80    }
81
82    pub fn forget_init(self) -> CircStack<MaybeUninit<T>, N> {
83        let CircStack { buffer, tail } = self;
84
85        CircStack {
86            buffer: buffer.map(MaybeUninit::new),
87            tail
88        }
89    }
90
91    // TODO: Verify this does what it should
92    pub const fn rotate(&mut self, offset: isize) {
93        if offset >= N as isize || offset <= -(N as isize) {
94            { ::core::panicking::panic_fmt(format_args!("TODO")); }panic!("TODO")
95        }
96
97        self.tail = (self.tail as isize + offset).rem_euclid(N as isize) as usize;
98    }
99
100    pub fn iter_mut(&mut self) -> IterMut<'_, T, N> {
101        self.into_iter()
102    }
103
104    pub fn iter(&self) -> Iter<'_, T, N> {
105        self.into_iter()
106    }
107}
108
109impl<T: Copy, const N: usize> CircStack<T, N> {
110    pub const fn repeat_item(item: T) -> CircStack<T, N> {
111        CircStack::new(
112            [item; N],
113            0
114        )
115    }
116
117    pub const fn pop_copy(&mut self) -> T {
118        let value = self.buffer[self.tail];
119        self.decrement();
120        value
121    }
122
123    pub const fn last(&self) -> &T {
124        &self.buffer[self.tail]
125    }
126}
127
128impl<T: Default, const N: usize> CircStack<T, N> {
129    pub fn pop_with_default(&mut self) -> T {
130        self.pop_with_replacement(T::default())
131    }
132}
133
134impl<T, const N: usize> CircStack<MaybeUninit<T>, N> {
135    pub const fn transpose(self) -> MaybeUninit<CircStack<T, N>> {
136        // Unfortunately, due to the variable size of the input and output, we have to copy here,
137        // and avoid calling drop on the original.
138
139        unsafe { mem::transmute_copy(&MaybeUninit::new(self)) }
140    }
141
142    pub const fn transpose_mut(&mut self) -> &mut MaybeUninit<CircStack<T, N>> {
143        unsafe { mem::transmute(self) }
144    }
145
146    pub const fn transpose_ref(&self) -> &MaybeUninit<CircStack<T, N>> {
147        unsafe { mem::transmute(self) }
148    }
149
150    pub const unsafe fn assume_init(self) -> CircStack<T, N> {
151        unsafe { self.transpose().assume_init() }
152    }
153
154    pub const unsafe fn assume_init_mut(&mut self) -> &mut CircStack<T, N> {
155        unsafe { self.transpose_mut().assume_init_mut() }
156    }
157
158    pub const unsafe fn assume_init_ref(&self) -> &CircStack<T, N> {
159        unsafe { self.transpose_ref().assume_init_ref() }
160    }
161}
162
163impl<T, const N: usize> CircStack<Option<T>, N> {
164    pub fn transpose(self) -> Option<CircStack<T, N>> {
165        let CircStack { buffer, tail } = self;
166
167        Some(CircStack {
168            buffer: buffer.transpose()?,
169            tail,
170        })
171    }
172}
173
174impl<T: Default, const N: usize> Default for CircStack<T, N> {
175    fn default() -> CircStack<T, N> {
176        CircStack::new(
177            [(); N].map(|_| T::default()),
178            0
179        )
180    }
181}
182
183impl<T: Copy, const N: usize> TryFrom<&[T]> for CircStack<T, N> {
184    type Error = TryFromSliceError;
185
186    fn try_from(value: &[T]) -> Result<Self, Self::Error> {
187        Ok(CircStack::new(
188            <[T; N]>::try_from(value)?,
189            0
190        ))
191    }
192}
193
194impl<T, const N: usize> From<[T; N]> for CircStack<T, N> {
195    fn from(buffer: [T; N]) -> Self {
196        CircStack::new(buffer, 0)
197    }
198}
199
200// TODO: Could impl Index<isize>, but is it already getting too confusing?
201
202impl<T, const N: usize> Index<usize> for CircStack<T, N> {
203    type Output = T;
204
205    fn index(&self, index: usize) -> &Self::Output {
206        &self.buffer[self.translate_index(index)]
207    }
208}
209
210impl<T, const N: usize> IndexMut<usize> for CircStack<T, N> {
211    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
212        &mut self.buffer[self.translate_index(index)]
213    }
214}