Skip to main content

structfs_core_store/
serde_impls.rs

1//! Serde implementations for the core types.
2//!
3//! - `Path`, `PathComponent`, `Format` serialize as strings.
4//! - `Value` serializes structurally (maps to JSON/CBOR/MessagePack shapes).
5//! - `Record` serializes as an externally tagged enum:
6//!   `{"parsed": <value>}` or `{"raw": {"bytes": [...], "format": "..."}}`.
7//!
8//! Note: `Value::Bytes` uses serde's byte-string type. Formats without a
9//! native byte type (JSON) encode it as an array of numbers, and
10//! deserializing that array back yields `Value::Array` — the bytes/array
11//! distinction survives only in formats with byte strings (CBOR,
12//! MessagePack).
13
14use std::collections::BTreeMap;
15use std::fmt;
16
17use serde::de::{self, MapAccess, SeqAccess, Visitor};
18use serde::ser::{SerializeMap, SerializeSeq};
19use serde::{Deserialize, Deserializer, Serialize, Serializer};
20
21use crate::{Format, Path, PathComponent, Record, Value};
22
23impl Serialize for Path {
24    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
25        serializer.collect_str(self)
26    }
27}
28
29impl<'de> Deserialize<'de> for Path {
30    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
31        let s = String::deserialize(deserializer)?;
32        Path::parse(&s).map_err(de::Error::custom)
33    }
34}
35
36impl Serialize for PathComponent {
37    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
38        serializer.serialize_str(self.as_str())
39    }
40}
41
42impl<'de> Deserialize<'de> for PathComponent {
43    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
44        let s = String::deserialize(deserializer)?;
45        PathComponent::try_new(s).map_err(de::Error::custom)
46    }
47}
48
49impl Serialize for Format {
50    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
51        serializer.serialize_str(self.as_str())
52    }
53}
54
55impl<'de> Deserialize<'de> for Format {
56    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
57        let s = String::deserialize(deserializer)?;
58        Ok(Format::new(s))
59    }
60}
61
62impl Serialize for Value {
63    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
64        match self {
65            Value::Null => serializer.serialize_unit(),
66            Value::Bool(b) => serializer.serialize_bool(*b),
67            Value::Integer(i) => serializer.serialize_i64(*i),
68            Value::Unsigned(i) => serializer.serialize_u64(*i),
69            Value::Float(f) => serializer.serialize_f64(*f),
70            Value::String(s) => serializer.serialize_str(s),
71            Value::Bytes(b) => serializer.serialize_bytes(b),
72            Value::Array(arr) => {
73                let mut seq = serializer.serialize_seq(Some(arr.len()))?;
74                for item in arr {
75                    seq.serialize_element(item)?;
76                }
77                seq.end()
78            }
79            Value::Map(map) => {
80                let mut m = serializer.serialize_map(Some(map.len()))?;
81                for (k, v) in map {
82                    m.serialize_entry(k, v)?;
83                }
84                m.end()
85            }
86        }
87    }
88}
89
90struct ValueVisitor;
91
92impl<'de> Visitor<'de> for ValueVisitor {
93    type Value = Value;
94
95    fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        f.write_str("a StructFS value")
97    }
98
99    fn visit_unit<E>(self) -> Result<Value, E> {
100        Ok(Value::Null)
101    }
102
103    fn visit_none<E>(self) -> Result<Value, E> {
104        Ok(Value::Null)
105    }
106
107    fn visit_some<D: Deserializer<'de>>(self, deserializer: D) -> Result<Value, D::Error> {
108        Value::deserialize(deserializer)
109    }
110
111    fn visit_bool<E>(self, b: bool) -> Result<Value, E> {
112        Ok(Value::Bool(b))
113    }
114
115    fn visit_i64<E>(self, i: i64) -> Result<Value, E> {
116        Ok(Value::Integer(i))
117    }
118
119    fn visit_u64<E: de::Error>(self, u: u64) -> Result<Value, E> {
120        Ok(Value::from(u))
121    }
122
123    fn visit_f64<E>(self, f: f64) -> Result<Value, E> {
124        Ok(Value::from(f))
125    }
126
127    fn visit_str<E>(self, s: &str) -> Result<Value, E> {
128        Ok(Value::String(s.to_string()))
129    }
130
131    fn visit_string<E>(self, s: String) -> Result<Value, E> {
132        Ok(Value::String(s))
133    }
134
135    fn visit_bytes<E>(self, b: &[u8]) -> Result<Value, E> {
136        Ok(Value::Bytes(b.to_vec()))
137    }
138
139    fn visit_byte_buf<E>(self, b: Vec<u8>) -> Result<Value, E> {
140        Ok(Value::Bytes(b))
141    }
142
143    fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Value, A::Error> {
144        let mut arr = Vec::new();
145        while let Some(item) = seq.next_element()? {
146            arr.push(item);
147        }
148        Ok(Value::Array(arr))
149    }
150
151    fn visit_map<A: MapAccess<'de>>(self, mut access: A) -> Result<Value, A::Error> {
152        let mut map = BTreeMap::new();
153        while let Some((k, v)) = access.next_entry::<String, Value>()? {
154            if map.contains_key(&k) {
155                return Err(de::Error::custom("duplicate map key"));
156            }
157            map.insert(k, v);
158        }
159        Ok(Value::Map(map))
160    }
161}
162
163impl<'de> Deserialize<'de> for Value {
164    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
165        deserializer.deserialize_any(ValueVisitor)
166    }
167}
168
169/// Wire representation of `Record`. Kept separate from `Record` itself so
170/// the in-memory type can hold `Bytes` and stay `#[non_exhaustive]`.
171#[derive(Serialize, Deserialize)]
172enum RecordRepr {
173    #[serde(rename = "raw")]
174    Raw { bytes: Vec<u8>, format: Format },
175    #[serde(rename = "parsed")]
176    Parsed(Value),
177}
178
179impl Serialize for Record {
180    fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
181        let repr = match self {
182            Record::Raw { bytes, format } => RecordRepr::Raw {
183                bytes: bytes.to_vec(),
184                format: format.clone(),
185            },
186            Record::Parsed(v) => RecordRepr::Parsed(v.clone()),
187        };
188        repr.serialize(serializer)
189    }
190}
191
192impl<'de> Deserialize<'de> for Record {
193    fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
194        Ok(match RecordRepr::deserialize(deserializer)? {
195            RecordRepr::Raw { bytes, format } => Record::raw(bytes, format),
196            RecordRepr::Parsed(v) => Record::Parsed(v),
197        })
198    }
199}
200
201#[cfg(test)]
202mod tests {
203    use super::*;
204    use crate::path;
205
206    #[test]
207    fn path_roundtrip() {
208        let p = path!("users/123/name");
209        let json = serde_json::to_string(&p).unwrap();
210        assert_eq!(json, "\"users/123/name\"");
211        let back: Path = serde_json::from_str(&json).unwrap();
212        assert_eq!(back, p);
213    }
214
215    #[test]
216    fn empty_path_roundtrip() {
217        let p = path!();
218        let json = serde_json::to_string(&p).unwrap();
219        assert_eq!(json, "\"\"");
220        let back: Path = serde_json::from_str(&json).unwrap();
221        assert!(back.is_empty());
222    }
223
224    #[test]
225    fn invalid_path_rejected() {
226        let result: Result<Path, _> = serde_json::from_str("\"bad-component\"");
227        assert!(result.is_err());
228    }
229
230    #[test]
231    fn path_component_roundtrip() {
232        let c = PathComponent::try_new("alice").unwrap();
233        let json = serde_json::to_string(&c).unwrap();
234        let back: PathComponent = serde_json::from_str(&json).unwrap();
235        assert_eq!(back, c);
236
237        let result: Result<PathComponent, _> = serde_json::from_str("\"bad name\"");
238        assert!(result.is_err());
239    }
240
241    #[test]
242    fn format_roundtrip() {
243        let json = serde_json::to_string(&Format::JSON).unwrap();
244        assert_eq!(json, "\"application/json\"");
245        let back: Format = serde_json::from_str(&json).unwrap();
246        assert_eq!(back, Format::JSON);
247    }
248
249    #[test]
250    fn value_roundtrip_via_json() {
251        let mut map = BTreeMap::new();
252        map.insert("name".to_string(), Value::from("Alice"));
253        map.insert("age".to_string(), Value::from(30i64));
254        map.insert("score".to_string(), Value::Float(0.5));
255        map.insert("active".to_string(), Value::Bool(true));
256        map.insert("nothing".to_string(), Value::Null);
257        map.insert(
258            "tags".to_string(),
259            Value::Array(vec![Value::from("a"), Value::from("b")]),
260        );
261        let value = Value::Map(map);
262
263        let json = serde_json::to_string(&value).unwrap();
264        let back: Value = serde_json::from_str(&json).unwrap();
265        assert_eq!(back, value);
266    }
267
268    #[test]
269    fn value_interops_with_serde_json() {
270        // A Value serializes to the JSON shape you'd expect
271        let value = Value::Map({
272            let mut m = BTreeMap::new();
273            m.insert("x".to_string(), Value::Integer(1));
274            m
275        });
276        let json: serde_json::Value = serde_json::to_value(&value).unwrap();
277        assert_eq!(json, serde_json::json!({"x": 1}));
278    }
279
280    #[test]
281    fn value_bytes_become_arrays_in_json() {
282        // JSON has no byte type: bytes serialize as arrays and come back as
283        // arrays. Documented limitation of self-describing formats.
284        let value = Value::Bytes(vec![1, 2, 3]);
285        let json = serde_json::to_string(&value).unwrap();
286        assert_eq!(json, "[1,2,3]");
287        let back: Value = serde_json::from_str(&json).unwrap();
288        assert_eq!(
289            back,
290            Value::Array(vec![
291                Value::Integer(1),
292                Value::Integer(2),
293                Value::Integer(3)
294            ])
295        );
296    }
297
298    #[test]
299    fn u64_range_preserved() {
300        let result: Result<Value, _> = serde_json::from_str("18446744073709551615");
301        assert_eq!(result.unwrap(), Value::Unsigned(u64::MAX));
302    }
303
304    #[test]
305    fn record_parsed_roundtrip() {
306        let record = Record::parsed(Value::from("hello"));
307        let json = serde_json::to_string(&record).unwrap();
308        assert_eq!(json, "{\"parsed\":\"hello\"}");
309        let back: Record = serde_json::from_str(&json).unwrap();
310        assert!(back.is_parsed());
311        assert_eq!(back.as_value(), Some(&Value::from("hello")));
312    }
313
314    #[test]
315    fn record_raw_roundtrip() {
316        let record = Record::raw(bytes::Bytes::from_static(b"{}"), Format::JSON);
317        let json = serde_json::to_string(&record).unwrap();
318        let back: Record = serde_json::from_str(&json).unwrap();
319        assert!(back.is_raw());
320        assert_eq!(back.format(), Format::JSON);
321        assert_eq!(back.as_bytes().map(|b| b.as_ref()), Some(b"{}".as_ref()));
322    }
323}