circular_array/
lib.rs

1pub mod iter;
2
3use std::fmt::{Debug, Display};
4use std::ops::{Add, Index, IndexMut};
5use crate::iter::CircularArrayIter;
6
7/// A circular array that allows infinite pushes into a fixed-size array.
8#[derive(Debug)]
9pub struct CircularArray<const N: usize, T> {
10    arr: [T;N],
11    start: usize,
12    len: usize,
13}
14
15impl<const N: usize, T> CircularArray<N, T> where T: Copy + Default + Debug + Display {
16    pub fn new() -> Self {
17        Self {
18            arr: [T::default(); N],
19            start: 0,
20            len: 0,
21        }
22    }
23
24    /// # example
25    /// ```
26    /// use circular_array::CircularArray;
27    /// #[test]
28    /// fn test_push() {
29    ///     let mut arr = CircularArray::<3, u32>::new();
30    ///     arr.push(1);
31    ///     arr.push(2);
32    ///     arr.push(3);
33    ///     assert_eq!(arr.to_array(), [1, 2, 3]);
34    ///     arr.push(4);
35    ///     assert_eq!(arr.to_array(), [2, 3, 4]);
36    /// }
37    /// ```
38
39    pub fn push(&mut self, item: T) {
40        if self.len >= N {
41            self.arr[self.start] = item;
42        } else {
43            self.arr[self.len] = item;
44        }
45        self.start = (self.start + 1) % N;
46        self.len += 1;
47    }
48
49    /// ## Examples
50    /// ```
51    ///     use circular_array::CircularArray;
52    /// #[test]
53    ///     fn test_to_array() {
54    ///         let mut arr = CircularArray::<3, u32>::new();
55    ///         arr.push(1);
56    ///         arr.push(2);
57    ///         arr.push(3);
58    ///         assert_eq!(arr.to_array(), [1, 2, 3]);
59    ///         arr.push(4);
60    ///         assert_eq!(arr.to_array(), [2, 3, 4]);
61    ///     }
62    /// ```
63    pub fn to_array(&self) -> [T;N] {
64        unsafe {
65            let mut arr = [T::default(); N];
66
67            let src_ptr = self.arr.as_ptr();
68            let dest_ptr = arr.as_mut_ptr();
69
70            if self.len >= N && self.start > 0 {
71                std::ptr::copy_nonoverlapping(src_ptr.add(self.start), dest_ptr, N - self.start);
72                std::ptr::copy_nonoverlapping(src_ptr, dest_ptr.add(N - self.start), N - self.start);
73            } else {
74                std::ptr::copy_nonoverlapping(src_ptr, dest_ptr, N);
75            }
76            arr
77        }
78    }
79
80    /// # example
81    /// ```
82    /// use circular_array::CircularArray;
83    /// let mut arr = CircularArray::<3, u32>::new();
84    /// arr.push(1);
85    /// arr.push(2);
86    /// arr.push(3);
87    /// let mut iter: circular_array::iter::CircularArrayIter<3, u32> = arr.iter();
88    /// assert_eq!(iter.next(), Some(&1));
89    /// assert_eq!(iter.next(), Some(&2));
90    /// assert_eq!(iter.next(), Some(&3));
91    /// assert_eq!(iter.next(), None);
92    /// ```
93    pub fn iter(&self) -> CircularArrayIter<N, T> {
94        CircularArrayIter::new(&self)
95    }
96
97
98    /// # Example
99    /// ```
100    /// use circular_array::CircularArray;
101    /// #[test]
102    /// fn test_last() {
103    ///     let mut arr = CircularArray::<3, u32>::new();
104    ///     assert_eq!(arr.last(), None);
105    ///     arr.push(1);
106    ///     assert_eq!(arr.last(), Some(1).as_ref());
107    ///     arr.push(2);
108    ///     arr.push(3);
109    ///     arr.push(4);
110    ///     assert_eq!(arr.last(), Some(4).as_ref());
111    /// }
112    /// ```
113    pub fn last(&self) -> Option<&T> {
114        if self.len >= N  {
115            Some(&self[N-1])
116        } else if self.len > 0 {
117            Some(&self[self.len -1])
118        } else {
119            None
120        }
121    }
122
123    pub fn len(&self) -> usize {
124        self.len
125    }
126}
127
128
129impl<T, const N: usize> Index<usize> for CircularArray<N, T> where [T]: Index<usize>, T: Default + Copy
130{
131    type Output = <[T] as Index<usize>>::Output;
132
133    #[inline]
134    fn index(&self, index: usize) -> &Self::Output {
135        if self.len >= N {
136            &self.arr[(self.start + index) % N]
137        } else {
138            &self.arr[index]
139        }
140    }
141}
142
143impl<T, const N: usize> IndexMut<usize> for CircularArray<N, T>
144    where [T]: Index<usize>,
145          T: Default + Copy, usize: Add<usize> {
146
147    #[inline]
148    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
149        if self.len >= N {
150            &mut self.arr[(self.start + index) % N]
151        } else {
152            &mut self.arr[index]
153        }
154    }
155}
156
157#[cfg(test)]
158mod tests {
159    use super::*;
160
161    #[test]
162    fn test_push() {
163        let mut arr = CircularArray::<3, u32>::new();
164        arr.push(1);
165        arr.push(2);
166        arr.push(3);
167        assert_eq!(arr.arr, [1, 2, 3]);
168        arr.push(4);
169        assert_eq!(arr.arr, [4, 2, 3]);
170    }
171
172    #[test]
173    #[allow(non_snake_case)]
174    fn test_Index_and_IndexMut() {
175        let mut arr = CircularArray::<3, u32>::new();
176        arr.push(0);
177        arr.push(0);
178        arr.push(0);
179        arr.push(0);
180        arr.push(0);
181        arr[0] = 1;
182        arr[1] = 2;
183        arr[2] = 3;
184        assert_eq!(arr[0], 1);
185        assert_eq!(arr[1], 2);
186        assert_eq!(arr[2], 3);
187    }
188
189    #[test]
190    fn test_to_array() {
191        let mut arr = CircularArray::<3, u32>::new();
192        arr.push(1);
193        arr.push(2);
194        arr.push(3);
195        assert_eq!(arr.to_array(), [1, 2, 3]);
196        arr.push(4);
197        assert_eq!(arr.to_array(), [2, 3, 4]);
198    }
199
200    #[test]
201    fn test_last() {
202        let mut arr = CircularArray::<3, u32>::new();
203        assert_eq!(arr.last(), None);
204        arr.push(1);
205        assert_eq!(arr.last(), Some(1).as_ref());
206        arr.push(2);
207        arr.push(3);
208        arr.push(4);
209        assert_eq!(arr.last(), Some(4).as_ref());
210    }
211
212    #[test]
213    fn test_len() {
214        let mut arr = CircularArray::<3, u32>::new();
215        assert_eq!(arr.len(), 0);
216        arr.push(1);
217        assert_eq!(arr.len(), 1);
218        arr.push(2);
219        arr.push(3);
220        arr.push(4);
221        assert_eq!(arr.len(), 4);
222    }
223}
224