Skip to main content

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    /// Returns a mutable reference to the underlying vec.
112    pub fn as_mut_vec(&mut self) -> &mut Vec<T> {
113        &mut self.data
114    }
115
116    // helpers
117    #[inline(always)]
118    pub(crate) fn panic_if_not_enough_room_for(&self, num_new_items: usize) {
119        assert!(
120            self.data.len() + num_new_items <= self.data.capacity(),
121            "{}",
122            ERR_MSG_OUT_OF_ROOM
123        );
124    }
125
126    #[inline(always)]
127    pub(crate) fn push_or_panic(&mut self, value: T) {
128        assert!(
129            self.data.len() < self.data.capacity(),
130            "{}",
131            ERR_MSG_OUT_OF_ROOM
132        );
133        self.data.push(value);
134    }
135}
136
137impl<T> From<Vec<T>> for FixedVec<T> {
138    fn from(data: Vec<T>) -> Self {
139        Self { data }
140    }
141}
142
143impl<T> From<FixedVec<T>> for Vec<T> {
144    fn from(value: FixedVec<T>) -> Self {
145        value.data
146    }
147}
148
149const ERR_MSG_OUT_OF_ROOM: &str =
150    "FixedVec is full, a fixed capacity vector cannot exceed its initial capacity.";
151
152#[cfg(test)]
153mod tests {
154    use alloc::vec;
155    use alloc::vec::Vec;
156
157    use crate::prelude::*;
158
159    #[test]
160    fn new() {
161        let vec: FixedVec<char> = FixedVec::new(17);
162        assert_eq!(0, vec.len());
163        assert!(vec.is_empty());
164        assert_eq!(17, vec.capacity());
165    }
166
167    #[test]
168    fn from() {
169        let vec = vec![1, 3, 42];
170        let fixed_vec: FixedVec<_> = vec.clone().into();
171        assert_eq!(&vec, fixed_vec.as_ref());
172        assert_eq!(vec.len(), fixed_vec.capacity());
173        let into_vec: Vec<_> = fixed_vec.into();
174        assert_eq!(&vec, &into_vec);
175
176        let mut vec = Vec::with_capacity(7);
177        vec.push(42);
178        let fixed_vec: FixedVec<_> = vec.clone().into();
179        assert_eq!(&vec, fixed_vec.as_ref());
180        assert_eq!(1, fixed_vec.capacity());
181        let into_vec: Vec<_> = fixed_vec.into();
182        assert_eq!(&vec, &into_vec);
183    }
184
185    #[test]
186    fn room() {
187        let mut vec = FixedVec::new(10);
188
189        for i in 0..vec.capacity() {
190            assert_eq!(i, vec.len());
191            assert_eq!(vec.capacity() - i, vec.room());
192            vec.push(1.1);
193        }
194
195        assert_eq!(vec.len(), vec.capacity());
196        assert_eq!(0, vec.room());
197        assert!(vec.is_full());
198    }
199
200    #[test]
201    fn as_slice() {
202        let fixed_vec: FixedVec<_> = (0..20).collect();
203        let vec: Vec<_> = (0..20).collect();
204
205        let slice = fixed_vec.as_slice();
206        assert_eq!(slice, &vec);
207    }
208
209    #[test]
210    fn panic_if_not_enough_room_for_when_ok() {
211        let mut vec = FixedVec::new(3);
212
213        vec.panic_if_not_enough_room_for(3);
214
215        vec.push("a");
216        vec.panic_if_not_enough_room_for(2);
217
218        vec.push("b");
219        vec.panic_if_not_enough_room_for(1);
220
221        vec.push("c");
222        vec.panic_if_not_enough_room_for(0);
223    }
224
225    #[test]
226    #[should_panic]
227    fn panic_if_not_enough_room_for_when_not_ok() {
228        let mut vec = FixedVec::new(3);
229        vec.push("a");
230        vec.panic_if_not_enough_room_for(3);
231    }
232
233    #[test]
234    fn push_or_panic_when_ok() {
235        let mut vec = FixedVec::new(3);
236
237        vec.push_or_panic(0);
238        vec.push_or_panic(1);
239        vec.push_or_panic(2);
240
241        assert_eq!(Some(&0), vec.get(0));
242        assert_eq!(Some(&1), vec.get(1));
243        assert_eq!(Some(&2), vec.get(2));
244    }
245    #[test]
246    #[should_panic]
247    fn push_or_panic_when_not_ok() {
248        let mut vec = FixedVec::new(3);
249
250        vec.push_or_panic(0);
251        vec.push_or_panic(1);
252        vec.push_or_panic(2);
253
254        assert_eq!(Some(&0), vec.get(0));
255        assert_eq!(Some(&1), vec.get(1));
256        assert_eq!(Some(&2), vec.get(2));
257
258        vec.push_or_panic(3);
259    }
260}