Skip to main content

facet_value/
serialize.rs

1//! Serialize any type implementing `Facet` into a [`Value`].
2//!
3//! This crate hosts the adapter between `facet-format`'s event serializer model
4//! and `facet-value`'s dynamic `Value` type.
5//!
6//! # Example
7//!
8//! ```
9//! use facet::Facet;
10//! use facet_value::{Value, from_value, to_value};
11//!
12//! #[derive(Debug, Facet, PartialEq)]
13//! struct Person {
14//!     name: String,
15//!     age: u32,
16//! }
17//!
18//! let person = Person { name: "Alice".into(), age: 30 };
19//! let value: Value = to_value(&person).unwrap();
20//!
21//! let person2: Person = from_value(value).unwrap();
22//! assert_eq!(person, person2);
23//! ```
24
25#![cfg_attr(not(feature = "std"), no_std)]
26#![warn(missing_docs)]
27
28extern crate alloc;
29
30use alloc::string::String;
31use alloc::vec::Vec;
32
33use crate::{VArray, VNumber, VObject, VString, Value};
34use facet_core::Facet;
35use facet_format::{FormatSerializer, ScalarValue, SerializeError, serialize_root};
36use facet_reflect::Peek;
37
38use crate::VBytes;
39
40/// Error type for `Value` serialization.
41#[derive(Debug)]
42pub struct ToValueError {
43    msg: String,
44}
45
46impl ToValueError {
47    /// Create a new error with the given message.
48    pub fn new(msg: impl Into<String>) -> Self {
49        Self { msg: msg.into() }
50    }
51}
52
53impl core::fmt::Display for ToValueError {
54    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
55        f.write_str(&self.msg)
56    }
57}
58
59impl core::error::Error for ToValueError {}
60
61/// Serializer that builds a [`Value`] from a sequence of format events.
62struct ValueSerializer {
63    stack: Vec<StackFrame>,
64    result: Option<Value>,
65}
66
67enum StackFrame {
68    Object {
69        obj: VObject,
70        pending_key: Option<String>,
71    },
72    Array {
73        arr: VArray,
74    },
75}
76
77impl ValueSerializer {
78    fn new() -> Self {
79        Self {
80            stack: Vec::new(),
81            result: None,
82        }
83    }
84
85    fn finish(self) -> Value {
86        self.result.unwrap_or(Value::NULL)
87    }
88
89    fn emit(&mut self, value: Value) {
90        match self.stack.last_mut() {
91            Some(StackFrame::Object { obj, pending_key }) => {
92                if let Some(key) = pending_key.take() {
93                    obj.insert(key, value);
94                } else {
95                    panic!("emit called on object without pending key");
96                }
97            }
98            Some(StackFrame::Array { arr }) => {
99                arr.push(value);
100            }
101            None => {
102                self.result = Some(value);
103            }
104        }
105    }
106}
107
108impl FormatSerializer for ValueSerializer {
109    type Error = ToValueError;
110
111    fn begin_struct(&mut self) -> Result<(), Self::Error> {
112        self.stack.push(StackFrame::Object {
113            obj: VObject::new(),
114            pending_key: None,
115        });
116        Ok(())
117    }
118
119    fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
120        match self.stack.last_mut() {
121            Some(StackFrame::Object { pending_key, .. }) => {
122                *pending_key = Some(key.to_string());
123                Ok(())
124            }
125            _ => Err(ToValueError::new("field_key called outside of object")),
126        }
127    }
128
129    fn end_struct(&mut self) -> Result<(), Self::Error> {
130        match self.stack.pop() {
131            Some(StackFrame::Object { obj, .. }) => {
132                self.emit(obj.into());
133                Ok(())
134            }
135            _ => Err(ToValueError::new(
136                "end_struct called without matching begin_struct",
137            )),
138        }
139    }
140
141    fn begin_seq(&mut self) -> Result<(), Self::Error> {
142        self.stack.push(StackFrame::Array { arr: VArray::new() });
143        Ok(())
144    }
145
146    fn end_seq(&mut self) -> Result<(), Self::Error> {
147        match self.stack.pop() {
148            Some(StackFrame::Array { arr }) => {
149                self.emit(arr.into());
150                Ok(())
151            }
152            _ => Err(ToValueError::new(
153                "end_seq called without matching begin_seq",
154            )),
155        }
156    }
157
158    fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
159        let value = match scalar {
160            ScalarValue::Unit | ScalarValue::Null => Value::NULL,
161            ScalarValue::Bool(b) => Value::from(b),
162            ScalarValue::Char(c) => VString::new(&c.to_string()).into(),
163            ScalarValue::I64(n) => VNumber::from_i64(n).into(),
164            ScalarValue::U64(n) => VNumber::from_u64(n).into(),
165            ScalarValue::I128(n) => VString::new(&n.to_string()).into(),
166            ScalarValue::U128(n) => VString::new(&n.to_string()).into(),
167            ScalarValue::F64(n) => VNumber::from_f64(n).map(Into::into).unwrap_or(Value::NULL),
168            ScalarValue::Str(s) => VString::new(&s).into(),
169            ScalarValue::Bytes(b) => VBytes::new(b.as_ref()).into(),
170        };
171        self.emit(value);
172        Ok(())
173    }
174}
175
176/// Serialize a value implementing `Facet` into a [`Value`].
177pub fn to_value<'facet, T: Facet<'facet>>(
178    value: &T,
179) -> Result<Value, SerializeError<ToValueError>> {
180    let mut serializer = ValueSerializer::new();
181    serialize_root(&mut serializer, Peek::new(value))?;
182    Ok(serializer.finish())
183}
184
185/// Serialize a [`Peek`] instance into a [`Value`].
186pub fn peek_to_value<'mem, 'facet>(
187    peek: Peek<'mem, 'facet>,
188) -> Result<Value, SerializeError<ToValueError>> {
189    let mut serializer = ValueSerializer::new();
190    serialize_root(&mut serializer, peek)?;
191    Ok(serializer.finish())
192}
193
194#[cfg(test)]
195mod tests {
196    use super::*;
197    use alloc::collections::BTreeMap;
198    use alloc::string::ToString;
199    use alloc::vec;
200
201    #[test]
202    fn test_to_value_primitives() {
203        let v = to_value(&true).unwrap();
204        assert_eq!(v.as_bool(), Some(true));
205
206        let v = to_value(&false).unwrap();
207        assert_eq!(v.as_bool(), Some(false));
208
209        let v = to_value(&42i32).unwrap();
210        assert_eq!(v.as_number().unwrap().to_i64(), Some(42));
211
212        let v = to_value(&123u64).unwrap();
213        assert_eq!(v.as_number().unwrap().to_u64(), Some(123));
214
215        let v = to_value(&2.5f64).unwrap();
216        assert!((v.as_number().unwrap().to_f64().unwrap() - 2.5).abs() < 0.001);
217
218        let s = "hello".to_string();
219        let v = to_value(&s).unwrap();
220        assert_eq!(v.as_string().unwrap().as_str(), "hello");
221    }
222
223    #[test]
224    fn test_to_value_option() {
225        let some: Option<i32> = Some(42);
226        let v = to_value(&some).unwrap();
227        assert_eq!(v.as_number().unwrap().to_i64(), Some(42));
228
229        let none: Option<i32> = None;
230        let v = to_value(&none).unwrap();
231        assert!(v.is_null());
232    }
233
234    #[test]
235    fn test_to_value_vec() {
236        let vec = vec![1i32, 2, 3];
237        let v = to_value(&vec).unwrap();
238
239        let arr = v.as_array().unwrap();
240        assert_eq!(arr.len(), 3);
241        assert_eq!(arr.get(0).unwrap().as_number().unwrap().to_i64(), Some(1));
242        assert_eq!(arr.get(1).unwrap().as_number().unwrap().to_i64(), Some(2));
243        assert_eq!(arr.get(2).unwrap().as_number().unwrap().to_i64(), Some(3));
244    }
245
246    #[test]
247    fn test_to_value_map() {
248        let mut map: BTreeMap<String, i32> = BTreeMap::new();
249        map.insert("a".to_string(), 1);
250        map.insert("b".to_string(), 2);
251
252        let v = to_value(&map).unwrap();
253
254        let obj = v.as_object().unwrap();
255        assert_eq!(obj.get("a").unwrap().as_number().unwrap().to_i64(), Some(1));
256        assert_eq!(obj.get("b").unwrap().as_number().unwrap().to_i64(), Some(2));
257    }
258
259    #[test]
260    fn test_to_value_nested() {
261        let vec = vec![Some(1i32), None, Some(3)];
262        let v = to_value(&vec).unwrap();
263
264        let arr = v.as_array().unwrap();
265        assert_eq!(arr.len(), 3);
266        assert_eq!(arr.get(0).unwrap().as_number().unwrap().to_i64(), Some(1));
267        assert!(arr.get(1).unwrap().is_null());
268        assert_eq!(arr.get(2).unwrap().as_number().unwrap().to_i64(), Some(3));
269    }
270
271    #[test]
272    fn test_roundtrip_value() {
273        let original = crate::value!({
274            "name": "Alice",
275            "age": 30,
276            "active": true
277        });
278
279        let v = to_value(&original).unwrap();
280        assert_eq!(v, original);
281    }
282}