orx_fixed_vec/
fixed_vec.rs

1use alloc::vec::Vec;
2
3/// A fixed vector, `FixedVec`, is a vector with a strict predetermined capacity
4/// (see [`SplitVec`](https://crates.io/crates/orx-split-vec) for dynamic capacity version).
5///
6/// It provides the following features:
7///
8/// * It provides operations with the same complexity and speed as the standard vector.
9/// * It makes sure that the data stays **pinned** in place.
10///     * `FixedVec<T>` implements [`PinnedVec<T>`](https://crates.io/crates/orx-pinned-vec) for any `T`;
11///     * `FixedVec<T>` implements `PinnedVecSimple<T>` for `T: NotSelfRefVecItem`;
12///     * Memory location of an item added to the fixed vector will never change
13///       unless the vector is dropped or cleared.
14///     * This allows the fixed vec to be converted into an [`ImpVec`](https://crates.io/crates/orx-imp-vec)
15///       to enable immutable-push operations which allows for
16///       convenient, efficient and safe implementations of self-referencing data structures.
17pub struct FixedVec<T> {
18    pub(crate) data: Vec<T>,
19}
20
21impl<T> FixedVec<T> {
22    /// Creates a new vector with the given fixed capacity.
23    ///
24    /// Note that the vector can never grow beyond this capacity.
25    ///
26    /// # Examples
27    ///
28    /// ```rust
29    /// use orx_fixed_vec::prelude::*;
30    ///
31    /// let mut vec = FixedVec::new(7);
32    /// vec.push(42);
33    ///
34    /// assert_eq!(7, vec.capacity());
35    /// ```
36    pub fn new(fixed_capacity: usize) -> Self {
37        Self {
38            data: Vec::with_capacity(fixed_capacity),
39        }
40    }
41
42    /// Returns the fixed vector into inner standard vector.
43    ///
44    /// # Examples
45    ///
46    /// ```
47    /// use orx_fixed_vec::prelude::*;
48    ///
49    /// let mut fixed_vec = FixedVec::new(64);
50    /// fixed_vec.push('a');
51    /// fixed_vec.push('b');
52    /// assert_eq!(fixed_vec.as_slice(), &['a', 'b']);
53    ///
54    /// let vec = fixed_vec.into_inner();
55    /// assert_eq!(vec.as_slice(), &['a', 'b']);
56    ///
57    /// let fixed_vec: FixedVec<_> = vec.into();
58    /// assert_eq!(fixed_vec.as_slice(), &['a', 'b']);
59    /// ```
60    pub fn into_inner(self) -> Vec<T> {
61        self.data
62    }
63
64    /// Returns the available room for new items; i.e.,
65    /// `capacity() - len()`.
66    ///
67    /// # Examples
68    ///
69    /// ```rust
70    /// use orx_fixed_vec::prelude::*;
71    ///
72    /// let mut vec = FixedVec::new(7);
73    /// vec.push(42);
74    ///
75    /// assert_eq!(7, vec.capacity());
76    /// assert_eq!(1, vec.len());
77    /// assert_eq!(6, vec.room());
78    /// ```
79    pub fn room(&self) -> usize {
80        self.data.capacity() - self.data.len()
81    }
82
83    /// Return whether the fixed vector is full or not;
84    /// equivalent to `capacity() == len()` or `room() == 0`.
85    ///
86    /// # Examples
87    ///
88    /// ```rust
89    /// use orx_fixed_vec::prelude::*;
90    ///
91    /// let mut vec = FixedVec::new(2);
92    /// assert!(!vec.is_full());
93    ///
94    /// vec.push(42);
95    /// assert!(!vec.is_full());
96    ///
97    /// vec.push(7);
98    /// assert!(vec.is_full());
99    /// ```
100    pub fn is_full(&self) -> bool {
101        self.data.capacity() == self.data.len()
102    }
103
104    /// Extracts a slice containing the entire vector.
105    ///
106    /// Equivalent to &s[..].
107    pub fn as_slice(&self) -> &[T] {
108        self.data.as_slice()
109    }
110
111    // helpers
112    #[inline(always)]
113    pub(crate) fn panic_if_not_enough_room_for(&self, num_new_items: usize) {
114        assert!(
115            self.data.len() + num_new_items <= self.data.capacity(),
116            "{}",
117            ERR_MSG_OUT_OF_ROOM
118        );
119    }
120
121    #[inline(always)]
122    pub(crate) fn push_or_panic(&mut self, value: T) {
123        assert!(
124            self.data.len() < self.data.capacity(),
125            "{}",
126            ERR_MSG_OUT_OF_ROOM
127        );
128        self.data.push(value);
129    }
130}
131
132impl<T> From<Vec<T>> for FixedVec<T> {
133    fn from(data: Vec<T>) -> Self {
134        Self { data }
135    }
136}
137
138impl<T> From<FixedVec<T>> for Vec<T> {
139    fn from(value: FixedVec<T>) -> Self {
140        value.data
141    }
142}
143
144const ERR_MSG_OUT_OF_ROOM: &str =
145    "FixedVec is full, a fixed capacity vector cannot exceed its initial capacity.";
146
147#[cfg(test)]
148mod tests {
149    use alloc::vec;
150    use alloc::vec::Vec;
151
152    use crate::prelude::*;
153
154    #[test]
155    fn new() {
156        let vec: FixedVec<char> = FixedVec::new(17);
157        assert_eq!(0, vec.len());
158        assert!(vec.is_empty());
159        assert_eq!(17, vec.capacity());
160    }
161
162    #[test]
163    fn from() {
164        let vec = vec![1, 3, 42];
165        let fixed_vec: FixedVec<_> = vec.clone().into();
166        assert_eq!(&vec, fixed_vec.as_ref());
167        assert_eq!(vec.len(), fixed_vec.capacity());
168        let into_vec: Vec<_> = fixed_vec.into();
169        assert_eq!(&vec, &into_vec);
170
171        let mut vec = Vec::with_capacity(7);
172        vec.push(42);
173        let fixed_vec: FixedVec<_> = vec.clone().into();
174        assert_eq!(&vec, fixed_vec.as_ref());
175        assert_eq!(1, fixed_vec.capacity());
176        let into_vec: Vec<_> = fixed_vec.into();
177        assert_eq!(&vec, &into_vec);
178    }
179
180    #[test]
181    fn room() {
182        let mut vec = FixedVec::new(10);
183
184        for i in 0..vec.capacity() {
185            assert_eq!(i, vec.len());
186            assert_eq!(vec.capacity() - i, vec.room());
187            vec.push(1.1);
188        }
189
190        assert_eq!(vec.len(), vec.capacity());
191        assert_eq!(0, vec.room());
192        assert!(vec.is_full());
193    }
194
195    #[test]
196    fn as_slice() {
197        let fixed_vec: FixedVec<_> = (0..20).collect();
198        let vec: Vec<_> = (0..20).collect();
199
200        let slice = fixed_vec.as_slice();
201        assert_eq!(slice, &vec);
202    }
203
204    #[test]
205    fn panic_if_not_enough_room_for_when_ok() {
206        let mut vec = FixedVec::new(3);
207
208        vec.panic_if_not_enough_room_for(3);
209
210        vec.push("a");
211        vec.panic_if_not_enough_room_for(2);
212
213        vec.push("b");
214        vec.panic_if_not_enough_room_for(1);
215
216        vec.push("c");
217        vec.panic_if_not_enough_room_for(0);
218    }
219
220    #[test]
221    #[should_panic]
222    fn panic_if_not_enough_room_for_when_not_ok() {
223        let mut vec = FixedVec::new(3);
224        vec.push("a");
225        vec.panic_if_not_enough_room_for(3);
226    }
227
228    #[test]
229    fn push_or_panic_when_ok() {
230        let mut vec = FixedVec::new(3);
231
232        vec.push_or_panic(0);
233        vec.push_or_panic(1);
234        vec.push_or_panic(2);
235
236        assert_eq!(Some(&0), vec.get(0));
237        assert_eq!(Some(&1), vec.get(1));
238        assert_eq!(Some(&2), vec.get(2));
239    }
240    #[test]
241    #[should_panic]
242    fn push_or_panic_when_not_ok() {
243        let mut vec = FixedVec::new(3);
244
245        vec.push_or_panic(0);
246        vec.push_or_panic(1);
247        vec.push_or_panic(2);
248
249        assert_eq!(Some(&0), vec.get(0));
250        assert_eq!(Some(&1), vec.get(1));
251        assert_eq!(Some(&2), vec.get(2));
252
253        vec.push_or_panic(3);
254    }
255}