Skip to main content

dioxus_const_vec/
lib.rs

1use std::{fmt::Debug, hash::Hash, mem::MaybeUninit};
2
3const DEFAULT_MAX_SIZE: usize = 2usize.pow(10);
4
5/// A buffer that can be read from at compile time.
6///
7/// This is very similar to [`std::io::Cursor`], but it is designed to be used
8/// in const contexts.
9#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct ConstReadBuffer<'a> {
11    location: usize,
12    memory: &'a [u8],
13}
14
15impl<'a> ConstReadBuffer<'a> {
16    /// Create a new buffer from a byte slice.
17    pub const fn new(memory: &'a [u8]) -> Self {
18        Self {
19            location: 0,
20            memory,
21        }
22    }
23
24    /// Get the next byte from the buffer.
25    ///
26    /// Returns `None` if the buffer is empty. Otherwise this returns the new
27    /// buffer state along with the byte that was read.
28    pub const fn get(mut self) -> Option<(Self, u8)> {
29        if self.location >= self.memory.len() {
30            return None;
31        }
32        let value = self.memory[self.location];
33        self.location += 1;
34        Some((self, value))
35    }
36
37    /// Get a reference to the underlying byte slice.
38    pub const fn as_ref(&self) -> &[u8] {
39        self.memory
40    }
41
42    /// Get a slice of the buffer from the current location to the end.
43    pub const fn remaining(&self) -> &[u8] {
44        self.memory.split_at(self.location).1
45    }
46}
47
48/// A version of [`Vec`] that is usable in const contexts.
49///
50/// `ConstVec` has a fixed maximum size, but it can grow and shrink within that
51/// size limit as needed.
52///
53/// # Example
54///
55/// ```rust
56/// # use dioxus_const_vec::ConstVec;
57/// const VEC: ConstVec<u8> = {
58///     let mut vec = ConstVec::new();
59///     vec.push(1);
60///     vec.push(2);
61///     vec.push(3);
62///     vec.push(4);
63///     assert!(vec.pop().unwrap() == 4);
64///     vec
65/// };
66///
67/// assert_eq!(VEC.as_ref(), &[1, 2, 3]);
68/// ```
69pub struct ConstVec<T, const MAX_SIZE: usize = DEFAULT_MAX_SIZE> {
70    memory: [MaybeUninit<T>; MAX_SIZE],
71    len: u32,
72}
73
74impl<T: Clone, const MAX_SIZE: usize> Clone for ConstVec<T, MAX_SIZE> {
75    fn clone(&self) -> Self {
76        let mut cloned = Self::new_with_max_size();
77        for i in 0..self.len as usize {
78            cloned.push(self.get(i).unwrap().clone());
79        }
80        cloned
81    }
82}
83
84impl<T: Copy, const MAX_SIZE: usize> Copy for ConstVec<T, MAX_SIZE> {}
85
86impl<T: PartialEq, const MAX_SIZE: usize> PartialEq for ConstVec<T, MAX_SIZE> {
87    fn eq(&self, other: &Self) -> bool {
88        self.as_ref() == other.as_ref()
89    }
90}
91
92impl<T: Hash, const MAX_SIZE: usize> Hash for ConstVec<T, MAX_SIZE> {
93    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
94        self.as_ref().hash(state)
95    }
96}
97
98impl<T, const MAX_SIZE: usize> Default for ConstVec<T, MAX_SIZE> {
99    fn default() -> Self {
100        Self::new_with_max_size()
101    }
102}
103
104impl<T: Debug, const MAX_SIZE: usize> Debug for ConstVec<T, MAX_SIZE> {
105    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
106        f.debug_struct("ConstVec")
107            .field("len", &self.len)
108            .field("memory", &self.as_ref())
109            .finish()
110    }
111}
112
113impl<T> ConstVec<T> {
114    /// Create a new empty [`ConstVec`].
115    pub const fn new() -> Self {
116        Self::new_with_max_size()
117    }
118}
119
120impl<T, const MAX_SIZE: usize> ConstVec<T, MAX_SIZE> {
121    /// Create a new empty [`ConstVec`] with a custom maximum size.
122    ///
123    /// # Example
124    ///
125    /// ```rust
126    /// # use dioxus_const_vec::ConstVec;
127    /// const EMPTY: ConstVec<u8, 10> = ConstVec::new_with_max_size();
128    /// assert!(EMPTY.is_empty());
129    /// ```
130    pub const fn new_with_max_size() -> Self {
131        Self {
132            memory: [const { MaybeUninit::uninit() }; MAX_SIZE],
133            len: 0,
134        }
135    }
136
137    /// Push a value onto the end of the [`ConstVec`].
138    ///
139    /// # Example
140    ///
141    /// ```rust
142    /// # use dioxus_const_vec::ConstVec;
143    /// const ONE: ConstVec<u8> = {
144    ///     let mut vec = ConstVec::new();
145    ///     vec.push(1);
146    ///     vec
147    /// };
148    /// assert_eq!(ONE.as_ref(), &[1]);
149    /// ```
150    pub const fn push(&mut self, value: T) {
151        if self.len as usize >= MAX_SIZE {
152            panic!("const vec capacity exceeded");
153        }
154        self.memory[self.len as usize] = MaybeUninit::new(value);
155        self.len += 1;
156    }
157
158    /// Extend the [`ConstVec`] with the contents of a slice.
159    ///
160    /// # Example
161    ///
162    /// ```rust
163    /// # use dioxus_const_vec::ConstVec;
164    /// const ONE: ConstVec<u8> = {
165    ///     let mut vec = ConstVec::new();
166    ///     vec.extend(&[1, 2, 3]);
167    ///     vec
168    /// };
169    /// assert_eq!(ONE.as_ref(), &[1, 2, 3]);
170    /// ```
171    pub const fn extend(&mut self, other: &[T])
172    where
173        T: Copy,
174    {
175        let mut i = 0;
176        while i < other.len() {
177            self.push(other[i]);
178            i += 1;
179        }
180    }
181
182    /// Get a reference to the value at the given index.
183    ///
184    /// # Example
185    ///
186    /// ```rust
187    /// # use dioxus_const_vec::ConstVec;
188    /// const ONE: ConstVec<u8> = {
189    ///     let mut vec = ConstVec::new();
190    ///     vec.push(1);
191    ///     vec
192    /// };
193    /// assert_eq!(ONE.get(0), Some(&1));
194    /// ```
195    pub const fn get(&self, index: usize) -> Option<&T> {
196        if index < self.len as usize {
197            Some(unsafe { &*self.memory[index].as_ptr() })
198        } else {
199            None
200        }
201    }
202
203    /// Get a copy of the value at the given index.
204    ///
205    /// This panics if `index` is out of bounds.
206    pub const fn at(&self, index: usize) -> T
207    where
208        T: Copy,
209    {
210        if index >= self.len as usize {
211            panic!("const vec index out of bounds");
212        }
213        unsafe { self.memory[index].assume_init() }
214    }
215
216    /// Get the length of the [`ConstVec`].
217    ///
218    /// # Example
219    ///
220    /// ```rust
221    /// # use dioxus_const_vec::ConstVec;
222    /// const ONE: ConstVec<u8> = {
223    ///     let mut vec = ConstVec::new();
224    ///     vec.push(1);
225    ///     vec
226    /// };
227    /// assert_eq!(ONE.len(), 1);
228    /// ```
229    pub const fn len(&self) -> usize {
230        self.len as usize
231    }
232
233    /// Check if the [`ConstVec`] is empty.
234    ///
235    /// # Example
236    ///
237    /// ```rust
238    /// # use dioxus_const_vec::ConstVec;
239    /// const EMPTY: ConstVec<u8> = ConstVec::new();
240    /// assert!(EMPTY.is_empty());
241    /// const ONE: ConstVec<u8> = {
242    ///     let mut vec = ConstVec::new();
243    ///     vec.push(1);
244    ///     vec
245    /// };
246    /// assert!(!ONE.is_empty());
247    /// ```
248    pub const fn is_empty(&self) -> bool {
249        self.len == 0
250    }
251
252    /// Get a reference to the underlying slice.
253    ///
254    /// # Example
255    ///
256    /// ```rust
257    /// # use dioxus_const_vec::ConstVec;
258    /// const ONE: ConstVec<u8> = {
259    ///     let mut vec = ConstVec::new();
260    ///     vec.push(1);
261    ///     vec
262    /// };
263    /// assert_eq!(ONE.as_ref(), &[1]);
264    /// ```
265    pub const fn as_ref(&self) -> &[T] {
266        unsafe {
267            &*(self.memory.split_at(self.len as usize).0 as *const [MaybeUninit<T>] as *const [T])
268        }
269    }
270
271    /// Get a reference to the underlying slice.
272    pub const fn as_slice(&self) -> &[T] {
273        self.as_ref()
274    }
275
276    /// Swap the values at the given indices.
277    ///
278    /// # Example
279    ///
280    /// ```rust
281    /// # use dioxus_const_vec::ConstVec;
282    /// const THREE: ConstVec<u8> = {
283    ///     let mut vec = ConstVec::new();
284    ///     vec.push(1);
285    ///     vec.push(2);
286    ///     vec.swap(0, 1);
287    ///     vec
288    /// };
289    /// assert_eq!(THREE.as_ref(), &[2, 1]);
290    /// ```
291    pub const fn swap(&mut self, first: usize, second: usize)
292    where
293        T: Copy,
294    {
295        assert!(first < self.len as usize);
296        assert!(second < self.len as usize);
297        let temp = self.memory[first];
298        self.memory[first] = self.memory[second];
299        self.memory[second] = temp;
300    }
301
302    /// Pop a value off the end of the [`ConstVec`].
303    ///
304    /// # Example
305    ///
306    /// ```rust
307    /// # use dioxus_const_vec::ConstVec;
308    /// const POPPED: (ConstVec<u8>, Option<u8>) = {
309    ///     let mut vec = ConstVec::new();
310    ///     vec.push(1);
311    ///     vec.push(2);
312    ///     vec.push(3);
313    ///     let popped = vec.pop();
314    ///     (vec, popped)
315    /// };
316    /// assert_eq!(POPPED.0.as_ref(), &[1, 2]);
317    /// assert_eq!(POPPED.1.unwrap(), 3);
318    /// ```
319    pub const fn pop(&mut self) -> Option<T>
320    where
321        T: Copy,
322    {
323        if self.len > 0 {
324            self.len -= 1;
325            let last = self.len as usize;
326            let last_value = unsafe { self.memory[last].assume_init() };
327            Some(last_value)
328        } else {
329            None
330        }
331    }
332
333    /// Remove the value at the given index.
334    ///
335    /// # Example
336    ///
337    /// ```rust
338    /// # use dioxus_const_vec::ConstVec;
339    /// const REMOVED: (ConstVec<u8>, Option<u8>) = {
340    ///     let mut vec = ConstVec::new();
341    ///     vec.push(1);
342    ///     vec.push(2);
343    ///     vec.push(3);
344    ///     let removed = vec.remove(1);
345    ///     (vec, removed)
346    /// };
347    /// assert_eq!(REMOVED.0.as_ref(), &[1, 3]);
348    /// assert_eq!(REMOVED.1.unwrap(), 2);
349    /// ```
350    pub const fn remove(&mut self, index: usize) -> Option<T>
351    where
352        T: Copy,
353    {
354        if index < self.len as usize {
355            let value = unsafe { self.memory[index].assume_init() };
356            let mut swap_index = index;
357            while swap_index + 1 < self.len as usize {
358                self.memory[swap_index] = self.memory[swap_index + 1];
359                swap_index += 1;
360            }
361            self.len -= 1;
362            Some(value)
363        } else {
364            None
365        }
366    }
367
368    /// Set the value at the given index.
369    ///
370    /// # Example
371    ///
372    /// ```rust
373    /// # use dioxus_const_vec::ConstVec;
374    /// const TWO: ConstVec<u8> = {
375    ///     let mut vec = ConstVec::new();
376    ///     vec.push(1);
377    ///     vec.set(0, 2);
378    ///     vec
379    /// };
380    /// assert_eq!(TWO.as_ref(), &[2]);
381    /// ```
382    pub const fn set(&mut self, index: usize, value: T) {
383        if index >= self.len as usize {
384            panic!("const vec index out of bounds")
385        }
386        self.memory[index] = MaybeUninit::new(value);
387    }
388
389    /// Split the [`ConstVec`] into two at the given index.
390    ///
391    /// # Example
392    ///
393    /// ```rust
394    /// # use dioxus_const_vec::ConstVec;
395    /// const SPLIT: (ConstVec<u8>, ConstVec<u8>) = {
396    ///     let mut vec = ConstVec::new();
397    ///     vec.push(1);
398    ///     vec.push(2);
399    ///     vec.push(3);
400    ///     vec.split_at(1)
401    /// };
402    /// assert_eq!(SPLIT.0.as_ref(), &[1]);
403    /// assert_eq!(SPLIT.1.as_ref(), &[2, 3]);
404    /// ```
405    pub const fn split_at(&self, index: usize) -> (Self, Self)
406    where
407        T: Copy,
408    {
409        assert!(index <= self.len as usize);
410        let slice = self.as_ref();
411        let (left, right) = slice.split_at(index);
412        let mut left_vec = Self::new_with_max_size();
413        let mut i = 0;
414        while i < left.len() {
415            left_vec.push(left[i]);
416            i += 1;
417        }
418        let mut right_vec = Self::new_with_max_size();
419        i = 0;
420        while i < right.len() {
421            right_vec.push(right[i]);
422            i += 1;
423        }
424        (left_vec, right_vec)
425    }
426}
427
428impl<const MAX_SIZE: usize> ConstVec<u8, MAX_SIZE> {
429    /// Convert the [`ConstVec`] into a [`ConstReadBuffer`].
430    ///
431    /// # Example
432    ///
433    /// ```rust
434    /// # use dioxus_const_vec::{ConstReadBuffer, ConstVec};
435    /// const TWO: ConstVec<u8> = {
436    ///     let mut vec = ConstVec::new();
437    ///     vec.push(1);
438    ///     vec.push(2);
439    ///     vec
440    /// };
441    /// const READ: ConstReadBuffer = TWO.read();
442    /// assert_eq!(READ.as_ref(), &[1, 2]);
443    /// ```
444    pub const fn read(&self) -> ConstReadBuffer<'_> {
445        ConstReadBuffer::new(self.as_ref())
446    }
447}
448
449#[test]
450fn test_const_vec() {
451    const VEC: ConstVec<u32> = {
452        let mut vec = ConstVec::new();
453        vec.push(1234);
454        vec.push(5678);
455        vec
456    };
457    assert_eq!(VEC.as_ref(), &[1234, 5678]);
458    let mut vec = VEC;
459    let value = vec.pop();
460    assert_eq!(value, Some(5678));
461    let value = vec.pop();
462    assert_eq!(value, Some(1234));
463    let value = vec.pop();
464    assert_eq!(value, None);
465    assert_eq!(vec.as_ref(), &[]);
466}
467
468#[test]
469fn test_const_vec_len() {
470    const VEC: ConstVec<u32> = {
471        let mut vec = ConstVec::new();
472        vec.push(1234);
473        vec.push(5678);
474        vec
475    };
476    assert_eq!(VEC.len(), 2);
477}
478
479#[test]
480fn test_const_vec_get() {
481    const VEC: ConstVec<u32> = {
482        let mut vec = ConstVec::new();
483        vec.push(1234);
484        vec.push(5678);
485        vec
486    };
487    assert_eq!(VEC.get(0), Some(&1234));
488    assert_eq!(VEC.get(1), Some(&5678));
489    assert_eq!(VEC.get(2), None);
490}
491
492#[test]
493fn test_const_vec_at() {
494    const VEC: ConstVec<u32> = {
495        let mut vec = ConstVec::new();
496        vec.push(1234);
497        vec.push(5678);
498        vec
499    };
500    assert_eq!(VEC.at(0), 1234);
501    assert_eq!(VEC.at(1), 5678);
502}
503
504#[test]
505fn test_const_vec_swap() {
506    const VEC: ConstVec<u32> = {
507        let mut vec = ConstVec::new();
508        vec.push(1234);
509        vec.push(5678);
510        vec
511    };
512    let mut vec = VEC;
513    assert_eq!(vec.as_ref(), &[1234, 5678]);
514    vec.swap(0, 1);
515    assert_eq!(vec.as_ref(), &[5678, 1234]);
516    vec.swap(0, 1);
517    assert_eq!(vec.as_ref(), &[1234, 5678]);
518}
519
520#[test]
521fn test_const_vec_remove() {
522    const VEC: ConstVec<u32> = {
523        let mut vec = ConstVec::new();
524        vec.push(1234);
525        vec.push(5678);
526        vec
527    };
528    let mut vec = VEC;
529    assert_eq!(vec.as_ref(), &[1234, 5678]);
530    let value = vec.remove(0);
531    assert_eq!(value, Some(1234));
532    assert_eq!(vec.as_ref(), &[5678]);
533    let value = vec.remove(0);
534    assert_eq!(value, Some(5678));
535    assert_eq!(vec.as_ref(), &[]);
536}
537
538#[test]
539fn test_const_vec_extend() {
540    const VEC: ConstVec<u32> = {
541        let mut vec = ConstVec::new();
542        vec.push(1234);
543        vec.push(5678);
544        vec.extend(&[91011, 1213]);
545        vec
546    };
547    let vec = VEC;
548    assert_eq!(vec.as_ref(), &[1234, 5678, 91011, 1213]);
549}