Skip to main content

haystack_core/data/
list.rs

1// Haystack List — an ordered list of Kind values.
2
3use crate::kinds::Kind;
4use std::fmt;
5
6/// Haystack List — a thin wrapper around `Vec<Kind>`.
7///
8/// Used for tag values that are lists of Haystack values.
9#[derive(Debug, Clone, Default, PartialEq)]
10pub struct HList(pub Vec<Kind>);
11
12impl HList {
13    /// Create an empty list.
14    pub fn new() -> Self {
15        Self::default()
16    }
17
18    /// Create a list from a pre-built Vec.
19    pub fn from_vec(v: Vec<Kind>) -> Self {
20        Self(v)
21    }
22
23    /// Returns the number of elements.
24    pub fn len(&self) -> usize {
25        self.0.len()
26    }
27
28    /// Returns `true` if the list is empty.
29    pub fn is_empty(&self) -> bool {
30        self.0.is_empty()
31    }
32
33    /// Returns a reference to the element at `index`, if in bounds.
34    pub fn get(&self, index: usize) -> Option<&Kind> {
35        self.0.get(index)
36    }
37
38    /// Append a value to the end of the list.
39    pub fn push(&mut self, val: Kind) {
40        self.0.push(val);
41    }
42
43    /// Iterate over the values.
44    pub fn iter(&self) -> impl Iterator<Item = &Kind> {
45        self.0.iter()
46    }
47}
48
49impl fmt::Display for HList {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "[")?;
52        for (i, item) in self.0.iter().enumerate() {
53            if i > 0 {
54                write!(f, ", ")?;
55            }
56            write!(f, "{item}")?;
57        }
58        write!(f, "]")
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    use crate::kinds::Number;
66
67    #[test]
68    fn empty_list() {
69        let l = HList::new();
70        assert!(l.is_empty());
71        assert_eq!(l.len(), 0);
72        assert_eq!(l.get(0), None);
73    }
74
75    #[test]
76    fn from_vec() {
77        let l = HList::from_vec(vec![Kind::Marker, Kind::Str("hello".into())]);
78        assert_eq!(l.len(), 2);
79        assert!(!l.is_empty());
80    }
81
82    #[test]
83    fn push_and_get() {
84        let mut l = HList::new();
85        l.push(Kind::Number(Number::unitless(1.0)));
86        l.push(Kind::Str("two".into()));
87        l.push(Kind::Marker);
88
89        assert_eq!(l.len(), 3);
90        assert_eq!(l.get(0), Some(&Kind::Number(Number::unitless(1.0))));
91        assert_eq!(l.get(1), Some(&Kind::Str("two".into())));
92        assert_eq!(l.get(2), Some(&Kind::Marker));
93        assert_eq!(l.get(3), None);
94    }
95
96    #[test]
97    fn iteration() {
98        let l = HList::from_vec(vec![
99            Kind::Number(Number::unitless(1.0)),
100            Kind::Number(Number::unitless(2.0)),
101            Kind::Number(Number::unitless(3.0)),
102        ]);
103
104        let collected: Vec<&Kind> = l.iter().collect();
105        assert_eq!(collected.len(), 3);
106    }
107
108    #[test]
109    fn equality() {
110        let a = HList::from_vec(vec![Kind::Marker, Kind::Str("x".into())]);
111        let b = HList::from_vec(vec![Kind::Marker, Kind::Str("x".into())]);
112        assert_eq!(a, b);
113    }
114
115    #[test]
116    fn inequality() {
117        let a = HList::from_vec(vec![Kind::Marker]);
118        let b = HList::from_vec(vec![Kind::NA]);
119        assert_ne!(a, b);
120    }
121
122    #[test]
123    fn display_empty() {
124        let l = HList::new();
125        assert_eq!(l.to_string(), "[]");
126    }
127
128    #[test]
129    fn display_with_items() {
130        let l = HList::from_vec(vec![
131            Kind::Number(Number::unitless(1.0)),
132            Kind::Str("hello".into()),
133        ]);
134        assert_eq!(l.to_string(), "[1, hello]");
135    }
136
137    #[test]
138    fn default_is_empty() {
139        let l = HList::default();
140        assert!(l.is_empty());
141    }
142}