1use alloc::string::String;
35use alloc::vec::Vec;
36
37use facet_core::Facet;
38use facet_format::{FormatSerializer, ScalarValue, SerializeError, serialize_root};
39use facet_reflect::Peek;
40
41use crate::{VArray, VNumber, VObject, VString, Value};
42
43#[derive(Debug)]
45pub struct ToValueError {
46 msg: String,
47}
48
49impl ToValueError {
50 pub fn new(msg: impl Into<String>) -> Self {
52 Self { msg: msg.into() }
53 }
54}
55
56impl core::fmt::Display for ToValueError {
57 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
58 f.write_str(&self.msg)
59 }
60}
61
62#[cfg(feature = "std")]
63impl core::error::Error for ToValueError {}
64
65struct ValueSerializer {
67 stack: Vec<StackFrame>,
69 result: Option<Value>,
71}
72
73enum StackFrame {
75 Object {
77 obj: VObject,
78 pending_key: Option<String>,
79 },
80 Array { arr: VArray },
82}
83
84impl ValueSerializer {
85 fn new() -> Self {
86 Self {
87 stack: Vec::new(),
88 result: None,
89 }
90 }
91
92 fn finish(self) -> Value {
93 self.result.unwrap_or(Value::NULL)
94 }
95
96 fn emit(&mut self, value: Value) {
97 match self.stack.last_mut() {
98 Some(StackFrame::Object { obj, pending_key }) => {
99 if let Some(key) = pending_key.take() {
100 obj.insert(key, value);
101 } else {
102 panic!("emit called on object without pending key");
104 }
105 }
106 Some(StackFrame::Array { arr }) => {
107 arr.push(value);
108 }
109 None => {
110 self.result = Some(value);
111 }
112 }
113 }
114}
115
116impl FormatSerializer for ValueSerializer {
117 type Error = ToValueError;
118
119 fn begin_struct(&mut self) -> Result<(), Self::Error> {
120 self.stack.push(StackFrame::Object {
121 obj: VObject::new(),
122 pending_key: None,
123 });
124 Ok(())
125 }
126
127 fn field_key(&mut self, key: &str) -> Result<(), Self::Error> {
128 match self.stack.last_mut() {
129 Some(StackFrame::Object { pending_key, .. }) => {
130 *pending_key = Some(key.to_string());
131 Ok(())
132 }
133 _ => Err(ToValueError::new("field_key called outside of object")),
134 }
135 }
136
137 fn end_struct(&mut self) -> Result<(), Self::Error> {
138 match self.stack.pop() {
139 Some(StackFrame::Object { obj, .. }) => {
140 self.emit(obj.into());
141 Ok(())
142 }
143 _ => Err(ToValueError::new(
144 "end_struct called without matching begin_struct",
145 )),
146 }
147 }
148
149 fn begin_seq(&mut self) -> Result<(), Self::Error> {
150 self.stack.push(StackFrame::Array { arr: VArray::new() });
151 Ok(())
152 }
153
154 fn end_seq(&mut self) -> Result<(), Self::Error> {
155 match self.stack.pop() {
156 Some(StackFrame::Array { arr }) => {
157 self.emit(arr.into());
158 Ok(())
159 }
160 _ => Err(ToValueError::new(
161 "end_seq called without matching begin_seq",
162 )),
163 }
164 }
165
166 fn scalar(&mut self, scalar: ScalarValue<'_>) -> Result<(), Self::Error> {
167 let value = match scalar {
168 ScalarValue::Unit | ScalarValue::Null => Value::NULL,
169 ScalarValue::Bool(b) => Value::from(b),
170 ScalarValue::Char(c) => VString::new(&c.to_string()).into(),
171 ScalarValue::I64(n) => VNumber::from_i64(n).into(),
172 ScalarValue::U64(n) => VNumber::from_u64(n).into(),
173 ScalarValue::I128(n) => {
174 VString::new(&n.to_string()).into()
176 }
177 ScalarValue::U128(n) => {
178 VString::new(&n.to_string()).into()
180 }
181 ScalarValue::F64(n) => VNumber::from_f64(n).map(Into::into).unwrap_or(Value::NULL),
182 ScalarValue::Str(s) => VString::new(&s).into(),
183 ScalarValue::Bytes(b) => crate::VBytes::new(b.as_ref()).into(),
184 };
185 self.emit(value);
186 Ok(())
187 }
188}
189
190pub fn to_value<'facet, T: Facet<'facet>>(
216 value: &T,
217) -> Result<Value, SerializeError<ToValueError>> {
218 let mut serializer = ValueSerializer::new();
219 serialize_root(&mut serializer, Peek::new(value))?;
220 Ok(serializer.finish())
221}
222
223pub fn peek_to_value<'mem, 'facet>(
244 peek: Peek<'mem, 'facet>,
245) -> Result<Value, SerializeError<ToValueError>> {
246 let mut serializer = ValueSerializer::new();
247 serialize_root(&mut serializer, peek)?;
248 Ok(serializer.finish())
249}
250
251#[cfg(test)]
252mod tests {
253 use super::*;
254 use alloc::collections::BTreeMap;
255 use alloc::string::ToString;
256 use alloc::vec;
257
258 #[test]
259 fn test_to_value_primitives() {
260 let v = to_value(&true).unwrap();
262 assert_eq!(v.as_bool(), Some(true));
263
264 let v = to_value(&false).unwrap();
265 assert_eq!(v.as_bool(), Some(false));
266
267 let v = to_value(&42i32).unwrap();
269 assert_eq!(v.as_number().unwrap().to_i64(), Some(42));
270
271 let v = to_value(&123u64).unwrap();
272 assert_eq!(v.as_number().unwrap().to_u64(), Some(123));
273
274 let v = to_value(&2.5f64).unwrap();
276 assert!((v.as_number().unwrap().to_f64().unwrap() - 2.5).abs() < 0.001);
277
278 let s = "hello".to_string();
280 let v = to_value(&s).unwrap();
281 assert_eq!(v.as_string().unwrap().as_str(), "hello");
282 }
283
284 #[test]
285 fn test_to_value_option() {
286 let some: Option<i32> = Some(42);
287 let v = to_value(&some).unwrap();
288 assert_eq!(v.as_number().unwrap().to_i64(), Some(42));
289
290 let none: Option<i32> = None;
291 let v = to_value(&none).unwrap();
292 assert!(v.is_null());
293 }
294
295 #[test]
296 fn test_to_value_vec() {
297 let vec = vec![1i32, 2, 3];
298 let v = to_value(&vec).unwrap();
299
300 let arr = v.as_array().unwrap();
301 assert_eq!(arr.len(), 3);
302 assert_eq!(arr.get(0).unwrap().as_number().unwrap().to_i64(), Some(1));
303 assert_eq!(arr.get(1).unwrap().as_number().unwrap().to_i64(), Some(2));
304 assert_eq!(arr.get(2).unwrap().as_number().unwrap().to_i64(), Some(3));
305 }
306
307 #[test]
308 fn test_to_value_map() {
309 let mut map: BTreeMap<String, i32> = BTreeMap::new();
310 map.insert("a".to_string(), 1);
311 map.insert("b".to_string(), 2);
312
313 let v = to_value(&map).unwrap();
314
315 let obj = v.as_object().unwrap();
316 assert_eq!(obj.get("a").unwrap().as_number().unwrap().to_i64(), Some(1));
317 assert_eq!(obj.get("b").unwrap().as_number().unwrap().to_i64(), Some(2));
318 }
319
320 #[test]
321 fn test_to_value_nested() {
322 let vec = vec![Some(1i32), None, Some(3)];
324 let v = to_value(&vec).unwrap();
325
326 let arr = v.as_array().unwrap();
327 assert_eq!(arr.len(), 3);
328 assert_eq!(arr.get(0).unwrap().as_number().unwrap().to_i64(), Some(1));
329 assert!(arr.get(1).unwrap().is_null());
330 assert_eq!(arr.get(2).unwrap().as_number().unwrap().to_i64(), Some(3));
331 }
332
333 #[test]
334 fn test_roundtrip_value() {
335 let original = crate::value!({
337 "name": "Alice",
338 "age": 30,
339 "active": true
340 });
341
342 let v = to_value(&original).unwrap();
343 assert_eq!(v, original);
344 }
345}