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}