devela/data/collections/list/const.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
// devela::data::collections::list:const
//
// This is a modified version of:
// [`const_list`](https://crates.io/crates/const_list/0.1.0)
use crate::ConstDefault;
/// A linked list node in a `ConstList`.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
struct ConstListItem<'a, T: 'a> {
/// The item represented by this node.
first: T,
/// The rest of the list.
rest: &'a ConstList<'a, T>,
}
/// An immutable, append-only, linear, functional, non-contiguous, list.
///
/// A safe, predictable, and lightweight structure, suitable where immutability
/// is an asset and compile-time guarantees matter more than list manipulation.
///
/// # Example
/// ```
/// # use devela::ConstList;
/// const MY_LIST: ConstList<'static, i32> = ConstList::new()
/// .push(2)
/// .push(4)
/// .push(8);
///
/// assert_eq!(8, *MY_LIST.pop().0.unwrap());
/// ```
#[must_use]
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct ConstList<'a, T: 'a>(Option<ConstListItem<'a, T>>);
impl<T> ConstDefault for ConstList<'_, T> {
const DEFAULT: Self = Self::new();
}
impl<'a, T: 'a> ConstList<'a, T> {
/// Creates a new, empty list.
pub const fn new() -> Self {
Self(None)
}
/// Gets a reference to the item at the provided index in this list, if any.
#[must_use]
pub const fn get(&self, index: usize) -> Option<&T> {
if let Some(value) = &self.0 {
if index == 0 {
Some(&value.first)
} else {
value.rest.get(index - 1)
}
} else {
None
}
}
/// Determines the length of this list.
#[must_use]
pub const fn len(&self) -> usize {
if let Some(value) = &self.0 {
value.rest.len() + 1
} else {
0
}
}
/// Whether the list is empty.
#[must_use]
pub const fn is_empty(&self) -> bool {
self.0.is_none()
}
/// Pushes a new item onto the beginning of this list,
/// producing a new list head.
pub const fn push(&'a self, value: T) -> Self {
ConstList(Some(ConstListItem { first: value, rest: self }))
}
/// Removes the first item (if any) from this list, and produces
/// the rest of the list.
pub const fn pop(&'a self) -> (Option<&'a T>, &'a Self) {
if let Some(value) = &self.0 {
(Some(&value.first), value.rest)
} else {
(None, self)
}
}
/// Creates an iterator over the contents of the list.
pub const fn iter(&self) -> ConstListIterator<T> {
ConstListIterator { target: self }
}
}
impl<'a, T> IntoIterator for &'a ConstList<'a, T> {
type Item = &'a T;
type IntoIter = ConstListIterator<'a, T>;
fn into_iter(self) -> Self::IntoIter {
ConstListIterator { target: self }
}
}
#[doc = crate::TAG_ITERATOR!()]
/// Iterates over the contents of a `ConstList`.
#[must_use]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ConstListIterator<'a, T> {
/// The current list head.
target: &'a ConstList<'a, T>,
}
impl<'a, T> Iterator for ConstListIterator<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
let (first, rest) = self.target.pop();
self.target = rest;
first
}
}