Skip to main content

libhaystack/haystack/encoding/json/
encode.rs

1// Copyright (C) 2020 - 2022, J2 Innovations
2
3//!
4//! Implement Hayson encoding
5//!
6
7use chrono::SecondsFormat;
8use std::borrow::Cow;
9
10use crate::{
11    haystack::val::{
12        Column, Coord, Date, DateTime, Dict, Grid, Marker, Na, Number, Ref, Remove, Symbol, Time,
13        Uri, Value as HVal, XStr,
14    },
15    val::HaystackDict,
16};
17
18use serde::ser::{Serialize, SerializeMap, SerializeSeq, Serializer};
19
20/// Serialize a Grid column
21impl Serialize for Column {
22    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
23        let mut map = serializer.serialize_map(Some(if self.meta.is_none() { 1 } else { 2 }))?;
24        map.serialize_entry("name", &self.name)?;
25        if self.meta.is_some() {
26            map.serialize_entry("meta", &self.meta)?;
27        }
28        map.end()
29    }
30}
31
32impl Serialize for Marker {
33    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
34        let mut map = serializer.serialize_map(Some(1))?;
35        map.serialize_entry("_kind", "marker")?;
36        map.end()
37    }
38}
39
40impl Serialize for Na {
41    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
42        let mut map = serializer.serialize_map(Some(1))?;
43        map.serialize_entry("_kind", "na")?;
44        map.end()
45    }
46}
47
48impl Serialize for Remove {
49    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
50        let mut map = serializer.serialize_map(Some(1))?;
51        map.serialize_entry("_kind", "remove")?;
52        map.end()
53    }
54}
55
56impl Serialize for Ref {
57    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
58        let mut map = serializer.serialize_map(Some(if self.dis.is_none() { 2 } else { 3 }))?;
59        map.serialize_entry("_kind", "ref")?;
60        map.serialize_entry("val", &self.value)?;
61        if self.dis.is_some() {
62            let dis = self.dis.clone();
63            map.serialize_entry("dis", &dis)?;
64        }
65        map.end()
66    }
67}
68
69impl Serialize for Uri {
70    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
71        let mut map = serializer.serialize_map(Some(2))?;
72        map.serialize_entry("_kind", "uri")?;
73        map.serialize_entry("val", &self.value)?;
74        map.end()
75    }
76}
77
78impl Serialize for Symbol {
79    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
80        let mut map = serializer.serialize_map(Some(2))?;
81        map.serialize_entry("_kind", "symbol")?;
82        map.serialize_entry("val", &self.value)?;
83        map.end()
84    }
85}
86
87impl Serialize for Number {
88    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
89        if let Some(unit) = self.unit {
90            let mut map = serializer.serialize_map(Some(3))?;
91            map.serialize_entry("_kind", "number")?;
92            map.serialize_entry("val", &self.value)?;
93            map.serialize_entry("unit", unit.symbol())?;
94            map.end()
95        } else if self.value.fract() == 0.0 {
96            serializer.serialize_i64(self.value as i64)
97        } else {
98            serializer.serialize_f64(self.value)
99        }
100    }
101}
102
103impl Serialize for Date {
104    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
105        let mut map = serializer.serialize_map(Some(2))?;
106        map.serialize_entry("_kind", "date")?;
107        map.serialize_entry("val", &self.to_string())?;
108        map.end()
109    }
110}
111
112impl Serialize for Time {
113    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
114        let mut map = serializer.serialize_map(Some(2))?;
115        map.serialize_entry("_kind", "time")?;
116        map.serialize_entry("val", &self.to_string())?;
117        map.end()
118    }
119}
120
121impl Serialize for DateTime {
122    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
123        let mut map = serializer.serialize_map(Some(2))?;
124        map.serialize_entry("_kind", "dateTime")?;
125        map.serialize_entry("val", &self.to_rfc3339_opts(SecondsFormat::AutoSi, true))?;
126        if !self.is_utc() {
127            map.serialize_entry("tz", &self.timezone_short_name())?;
128        }
129        map.end()
130    }
131}
132
133impl Serialize for Coord {
134    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
135        let mut map = serializer.serialize_map(Some(3))?;
136        map.serialize_entry("_kind", "coord")?;
137        map.serialize_entry("lat", &self.lat)?;
138        map.serialize_entry("lng", &self.long)?;
139        map.end()
140    }
141}
142
143impl Serialize for XStr {
144    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
145        let mut map = serializer.serialize_map(Some(3))?;
146        map.serialize_entry("_kind", "xstr")?;
147        map.serialize_entry("type", &self.r#type)?;
148        map.serialize_entry("val", &self.value)?;
149        map.end()
150    }
151}
152
153impl Serialize for Dict {
154    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
155        let mut map = serializer.serialize_map(Some(self.len()))?;
156        for (k, v) in self.iter() {
157            map.serialize_entry(k, v)?;
158        }
159        map.end()
160    }
161}
162
163impl Serialize for Grid {
164    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
165        let mut map = serializer.serialize_map(Some(4))?;
166        map.serialize_entry("_kind", "grid")?;
167
168        let meta = ensure_meta_has_ver(self.meta.as_ref());
169        map.serialize_entry("meta", meta.as_ref())?;
170
171        map.serialize_entry("cols", &self.columns)?;
172        map.serialize_entry("rows", &self.rows)?;
173        map.end()
174    }
175}
176
177fn ensure_meta_has_ver<'a>(meta: Option<&'a Dict>) -> Cow<'a, Dict> {
178    match meta {
179        Some(meta) if meta.has("ver") => Cow::Borrowed(meta),
180        Some(meta) => {
181            let mut with_ver = meta.clone();
182            with_ver.insert("ver".into(), "3.0".into());
183            Cow::Owned(with_ver)
184        }
185        None => {
186            let mut meta = Dict::new();
187            meta.insert("ver".into(), "3.0".into());
188            Cow::Owned(meta)
189        }
190    }
191}
192
193///
194/// Serializes a haystack value to Haystack JSON (Hayson)
195///
196impl Serialize for HVal {
197    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
198        match self {
199            HVal::Null => serializer.serialize_none(),
200
201            HVal::Remove => Remove::serialize(&Remove, serializer),
202
203            HVal::Marker => Marker::serialize(&Marker, serializer),
204
205            HVal::Bool(value) => serializer.serialize_bool(value.value),
206
207            HVal::Na => Na::serialize(&Na, serializer),
208
209            HVal::Number(val) => Number::serialize(val, serializer),
210
211            HVal::Str(val) => serializer.serialize_str(val.value.as_str()),
212
213            HVal::Ref(val) => Ref::serialize(val, serializer),
214
215            HVal::Symbol(val) => Symbol::serialize(val, serializer),
216
217            HVal::Uri(val) => Uri::serialize(val, serializer),
218
219            HVal::Date(val) => Date::serialize(val, serializer),
220
221            HVal::Time(val) => Time::serialize(val, serializer),
222
223            HVal::DateTime(val) => DateTime::serialize(val, serializer),
224
225            HVal::Coord(val) => Coord::serialize(val, serializer),
226
227            HVal::XStr(val) => XStr::serialize(val, serializer),
228
229            HVal::List(val) => {
230                let mut seq = serializer.serialize_seq(Some(val.len()))?;
231                for el in val {
232                    seq.serialize_element(el)?;
233                }
234                seq.end()
235            }
236
237            HVal::Dict(val) => Dict::serialize(val, serializer),
238
239            HVal::Grid(val) => Grid::serialize(val, serializer),
240        }
241    }
242}
243
244#[cfg(test)]
245mod tests {
246    use super::*;
247
248    #[test]
249    fn ensure_meta_has_ver_when_ver_exists() {
250        let mut meta = Dict::new();
251        meta.insert("ver".into(), "3.0".into());
252        meta.insert("site".into(), "alpha".into());
253
254        let result = ensure_meta_has_ver(Some(&meta));
255
256        assert!(result.has("ver"));
257        assert!(result.has("site"));
258    }
259
260    #[test]
261    fn ensure_meta_has_ver_when_missing() {
262        let mut meta = Dict::new();
263        meta.insert("site".into(), "alpha".into());
264
265        let result = ensure_meta_has_ver(Some(&meta));
266
267        assert!(result.has("ver"));
268        assert!(result.has("site"));
269        assert!(!meta.has("ver"));
270    }
271
272    #[test]
273    fn ensure_meta_has_ver_creates_meta_when_none() {
274        let result = ensure_meta_has_ver(None);
275
276        assert!(result.has("ver"));
277        assert_eq!(result.len(), 1);
278    }
279}