Skip to main content

haystack_core/kinds/
kind.rs

1use super::*;
2use chrono::{NaiveDate, NaiveTime};
3use std::fmt;
4
5/// The central Haystack value type. Every tag value is a Kind.
6#[derive(Debug, Clone, PartialEq)]
7pub enum Kind {
8    Null,
9    Marker,
10    NA,
11    Remove,
12    Bool(bool),
13    Number(Number),
14    Str(String),
15    Ref(HRef),
16    Uri(Uri),
17    Symbol(Symbol),
18    Date(NaiveDate),
19    Time(NaiveTime),
20    DateTime(HDateTime),
21    Coord(Coord),
22    XStr(XStr),
23    List(Vec<Kind>),
24    Dict(Box<crate::data::HDict>),
25    Grid(Box<crate::data::HGrid>),
26}
27
28impl fmt::Display for Kind {
29    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30        match self {
31            Kind::Null => write!(f, "null"),
32            Kind::Marker => write!(f, "{}", super::singletons::Marker),
33            Kind::NA => write!(f, "{}", super::singletons::NA),
34            Kind::Remove => write!(f, "{}", super::singletons::Remove),
35            Kind::Bool(v) => write!(f, "{v}"),
36            Kind::Number(n) => write!(f, "{n}"),
37            Kind::Str(s) => write!(f, "{s}"),
38            Kind::Ref(r) => write!(f, "{r}"),
39            Kind::Uri(u) => write!(f, "{u}"),
40            Kind::Symbol(s) => write!(f, "{s}"),
41            Kind::Date(d) => write!(f, "{d}"),
42            Kind::Time(t) => write!(f, "{}", t.format("%H:%M:%S")),
43            Kind::DateTime(dt) => write!(f, "{dt}"),
44            Kind::Coord(c) => write!(f, "{c}"),
45            Kind::XStr(x) => write!(f, "{x}"),
46            Kind::List(items) => {
47                write!(f, "[")?;
48                for (i, item) in items.iter().enumerate() {
49                    if i > 0 {
50                        write!(f, ", ")?;
51                    }
52                    write!(f, "{item}")?;
53                }
54                write!(f, "]")
55            }
56            Kind::Dict(d) => write!(f, "{d}"),
57            Kind::Grid(g) => write!(f, "{g}"),
58        }
59    }
60}
61
62// Convenience From implementations
63impl From<bool> for Kind {
64    fn from(v: bool) -> Self {
65        Kind::Bool(v)
66    }
67}
68
69impl From<Number> for Kind {
70    fn from(n: Number) -> Self {
71        Kind::Number(n)
72    }
73}
74
75impl From<HRef> for Kind {
76    fn from(r: HRef) -> Self {
77        Kind::Ref(r)
78    }
79}
80
81impl From<String> for Kind {
82    fn from(s: String) -> Self {
83        Kind::Str(s)
84    }
85}
86
87impl From<&str> for Kind {
88    fn from(s: &str) -> Self {
89        Kind::Str(s.to_string())
90    }
91}
92
93impl From<Uri> for Kind {
94    fn from(u: Uri) -> Self {
95        Kind::Uri(u)
96    }
97}
98
99impl From<Symbol> for Kind {
100    fn from(s: Symbol) -> Self {
101        Kind::Symbol(s)
102    }
103}
104
105impl From<Coord> for Kind {
106    fn from(c: Coord) -> Self {
107        Kind::Coord(c)
108    }
109}
110
111impl From<XStr> for Kind {
112    fn from(x: XStr) -> Self {
113        Kind::XStr(x)
114    }
115}
116
117impl From<NaiveDate> for Kind {
118    fn from(d: NaiveDate) -> Self {
119        Kind::Date(d)
120    }
121}
122
123impl From<NaiveTime> for Kind {
124    fn from(t: NaiveTime) -> Self {
125        Kind::Time(t)
126    }
127}
128
129impl From<HDateTime> for Kind {
130    fn from(dt: HDateTime) -> Self {
131        Kind::DateTime(dt)
132    }
133}
134
135#[cfg(test)]
136mod tests {
137    use super::*;
138
139    #[test]
140    fn kind_null() {
141        assert_eq!(Kind::Null.to_string(), "null");
142    }
143
144    #[test]
145    fn kind_marker() {
146        assert_eq!(Kind::Marker.to_string(), "\u{2713}");
147    }
148
149    #[test]
150    fn kind_bool() {
151        assert_eq!(Kind::Bool(true).to_string(), "true");
152        assert_eq!(Kind::Bool(false).to_string(), "false");
153    }
154
155    #[test]
156    fn kind_number() {
157        let k = Kind::Number(Number::new(72.5, Some("°F".into())));
158        assert_eq!(k.to_string(), "72.5°F");
159    }
160
161    #[test]
162    fn kind_str() {
163        let k = Kind::Str("hello".into());
164        assert_eq!(k.to_string(), "hello");
165    }
166
167    #[test]
168    fn kind_ref() {
169        let k = Kind::Ref(HRef::from_val("site-1"));
170        assert_eq!(k.to_string(), "@site-1");
171    }
172
173    #[test]
174    fn kind_list() {
175        let k = Kind::List(vec![
176            Kind::Number(Number::unitless(1.0)),
177            Kind::Str("two".into()),
178        ]);
179        assert_eq!(k.to_string(), "[1, two]");
180    }
181
182    #[test]
183    fn kind_equality() {
184        assert_eq!(Kind::Marker, Kind::Marker);
185        assert_ne!(Kind::Marker, Kind::NA);
186        assert_eq!(
187            Kind::Number(Number::unitless(42.0)),
188            Kind::Number(Number::unitless(42.0))
189        );
190    }
191
192    #[test]
193    fn kind_from_conversions() {
194        let _: Kind = true.into();
195        let _: Kind = Number::unitless(1.0).into();
196        let _: Kind = HRef::from_val("x").into();
197        let _: Kind = "hello".into();
198        let _: Kind = String::from("hello").into();
199    }
200}