1use core::num::NonZero;
2use facet_core::{Def, Facet, FieldAttribute, StructKind};
3use facet_reflect::Peek;
4use std::io::{self, Write};
5
6pub fn to_string<'a, T: Facet<'a>>(value: &T) -> String {
8 let peek = Peek::new(value);
9 let mut output = Vec::new();
10 serialize(&peek, &mut output).unwrap();
11 String::from_utf8(output).unwrap()
12}
13
14pub fn peek_to_string(peek: &Peek<'_, '_>) -> String {
16 let mut output = Vec::new();
17 serialize(peek, &mut output).unwrap();
18 String::from_utf8(output).unwrap()
19}
20
21pub fn to_writer<'a, T: Facet<'a>, W: Write>(value: &T, writer: &mut W) -> io::Result<()> {
23 let peek = Peek::new(value);
24 serialize(&peek, writer)
25}
26
27pub fn peek_to_writer<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
29 serialize(peek, writer)
30}
31
32fn serialize<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
34 use facet_core::{
35 StructDef,
36 StructKind::{Tuple, TupleStruct},
37 };
38
39 match peek.shape().def {
40 Def::Scalar(_) => serialize_scalar(peek, writer),
41 Def::Struct(StructDef {
42 kind: Tuple | TupleStruct,
43 ..
44 }) => serialize_tuple(peek, writer),
45 Def::Struct(_) => serialize_struct(peek, writer),
46 Def::List(_) => serialize_list(peek, writer),
47 Def::Map(_) => serialize_map(peek, writer),
48 Def::Enum(_) => serialize_enum(peek, writer),
49 Def::Option(_) => serialize_option(peek, writer),
50 _ => Err(io::Error::new(
51 io::ErrorKind::Other,
52 format!("Unsupported type: {}", peek.shape()),
53 )),
54 }
55}
56
57fn serialize_scalar<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
59 if peek.shape().is_type::<bool>() {
61 let value = peek.get::<bool>().unwrap();
62 write!(writer, "{}", if *value { "true" } else { "false" })
63 } else if peek.shape().is_type::<String>() {
64 let value = peek.get::<String>().unwrap();
65 write_json_string(writer, value)
66 } else if peek.shape().is_type::<&str>() {
67 let value = peek.get::<&str>().unwrap();
68 write_json_string(writer, value)
69 } else if peek.shape().is_type::<alloc::borrow::Cow<'_, str>>() {
70 let value = peek.get::<alloc::borrow::Cow<'_, str>>().unwrap();
71 write_json_string(writer, value)
72 }
73 else if peek.shape().is_type::<u8>() {
75 let value = peek.get::<u8>().unwrap();
76 write!(writer, "{}", value)
77 } else if peek.shape().is_type::<u16>() {
78 let value = peek.get::<u16>().unwrap();
79 write!(writer, "{}", value)
80 } else if peek.shape().is_type::<u32>() {
81 let value = peek.get::<u32>().unwrap();
82 write!(writer, "{}", value)
83 } else if peek.shape().is_type::<u64>() {
84 let value = peek.get::<u64>().unwrap();
85 write!(writer, "{}", value)
86 } else if peek.shape().is_type::<usize>() {
87 let value = peek.get::<usize>().unwrap();
88 write!(writer, "{}", value)
89 } else if peek.shape().is_type::<i8>() {
90 let value = peek.get::<i8>().unwrap();
91 write!(writer, "{}", value)
92 } else if peek.shape().is_type::<i16>() {
93 let value = peek.get::<i16>().unwrap();
94 write!(writer, "{}", value)
95 } else if peek.shape().is_type::<i32>() {
96 let value = peek.get::<i32>().unwrap();
97 write!(writer, "{}", value)
98 } else if peek.shape().is_type::<i64>() {
99 let value = peek.get::<i64>().unwrap();
100 write!(writer, "{}", value)
101 } else if peek.shape().is_type::<isize>() {
102 let value = peek.get::<isize>().unwrap();
103 write!(writer, "{}", value)
104 }
105 else if peek.shape().is_type::<NonZero<u8>>() {
107 let value = peek.get::<NonZero<u8>>().unwrap();
108 write!(writer, "{}", value)
109 } else if peek.shape().is_type::<NonZero<u16>>() {
110 let value = peek.get::<NonZero<u16>>().unwrap();
111 write!(writer, "{}", value)
112 } else if peek.shape().is_type::<NonZero<u32>>() {
113 let value = peek.get::<NonZero<u32>>().unwrap();
114 write!(writer, "{}", value)
115 } else if peek.shape().is_type::<NonZero<u64>>() {
116 let value = peek.get::<NonZero<u64>>().unwrap();
117 write!(writer, "{}", value)
118 } else if peek.shape().is_type::<NonZero<usize>>() {
119 let value = peek.get::<NonZero<usize>>().unwrap();
120 write!(writer, "{}", value)
121 } else if peek.shape().is_type::<NonZero<i8>>() {
122 let value = peek.get::<NonZero<i8>>().unwrap();
123 write!(writer, "{}", value)
124 } else if peek.shape().is_type::<NonZero<i16>>() {
125 let value = peek.get::<NonZero<i16>>().unwrap();
126 write!(writer, "{}", value)
127 } else if peek.shape().is_type::<NonZero<i32>>() {
128 let value = peek.get::<NonZero<i32>>().unwrap();
129 write!(writer, "{}", value)
130 } else if peek.shape().is_type::<NonZero<i64>>() {
131 let value = peek.get::<NonZero<i64>>().unwrap();
132 write!(writer, "{}", value)
133 } else if peek.shape().is_type::<NonZero<isize>>() {
134 let value = peek.get::<NonZero<isize>>().unwrap();
135 write!(writer, "{}", value)
136 }
137 else if peek.shape().is_type::<f32>() {
139 let value = peek.get::<f32>().unwrap();
140 write!(writer, "{}", value)
141 } else if peek.shape().is_type::<f64>() {
142 let value = peek.get::<f64>().unwrap();
143 write!(writer, "{}", value)
144 } else {
145 Err(io::Error::new(
146 io::ErrorKind::Other,
147 format!("Unsupported scalar type: {}", peek.shape()),
148 ))
149 }
150}
151
152fn serialize_struct<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
154 let struct_peek = peek
155 .into_struct()
156 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e)))?;
157
158 write!(writer, "{{")?;
159
160 let mut first = true;
161 for (field, field_peek) in struct_peek.fields_for_serialize() {
162 if !first {
163 write!(writer, ",")?;
164 }
165 first = false;
166
167 let field_name = field
169 .attributes
170 .iter()
171 .find_map(|attr| {
172 if let FieldAttribute::Rename(name) = attr {
173 Some(*name)
174 } else {
175 None
176 }
177 })
178 .unwrap_or(field.name);
179
180 write_json_string(writer, field_name)?;
182 write!(writer, ":")?;
183
184 serialize(&field_peek, writer)?;
186 }
187
188 write!(writer, "}}")?;
189
190 Ok(())
191}
192
193fn serialize_list<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
195 let list_peek = peek
196 .into_list()
197 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a list: {}", e)))?;
198
199 write!(writer, "[")?;
200
201 let mut first = true;
202 for item_peek in list_peek.iter() {
203 if !first {
204 write!(writer, ",")?;
205 }
206 first = false;
207
208 serialize(&item_peek, writer)?;
209 }
210
211 write!(writer, "]")?;
212
213 Ok(())
214}
215
216fn serialize_tuple<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
218 let struct_peek = peek
219 .into_struct()
220 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a struct: {}", e)))?;
221
222 write!(writer, "[")?;
223
224 let mut first = true;
225 for (_, item_peek) in struct_peek.fields_for_serialize() {
226 if !first {
227 write!(writer, ",")?;
228 }
229 first = false;
230
231 serialize(&item_peek, writer)?;
232 }
233
234 write!(writer, "]")?;
235
236 Ok(())
237}
238
239fn serialize_map<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
241 let map_peek = peek
242 .into_map()
243 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not a map: {}", e)))?;
244
245 write!(writer, "{{")?;
246
247 let mut first = true;
248 for (key, value) in map_peek.iter() {
249 if !first {
250 write!(writer, ",")?;
251 }
252 first = false;
253
254 match key.shape().def {
256 Def::Scalar(_) => {
257 if key.shape().is_type::<String>() {
259 let key_str = key.get::<String>().unwrap();
260 write_json_string(writer, key_str)?;
261 } else {
262 write!(writer, "\"{}\"", key)?;
264 }
265 }
266 _ => {
267 return Err(io::Error::new(
268 io::ErrorKind::Other,
269 format!("Map keys must be scalar types, got: {}", key.shape()),
270 ));
271 }
272 }
273
274 write!(writer, ":")?;
275
276 serialize(&value, writer)?;
278 }
279
280 write!(writer, "}}")?;
281
282 Ok(())
283}
284
285fn serialize_enum<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
287 let enum_peek = peek
288 .into_enum()
289 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not an enum: {}", e)))?;
290
291 let variant = enum_peek.active_variant();
292 let variant_name = variant.name;
293
294 if variant.data.fields.is_empty() {
296 write_json_string(writer, variant_name)
298 } else {
299 write!(writer, "{{")?;
301 write_json_string(writer, variant_name)?;
302 write!(writer, ":")?;
303
304 let is_struct = variant.data.kind == StructKind::Struct;
306
307 if is_struct {
308 write!(writer, "{{")?;
310
311 let mut first = true;
312 for (field, field_peek) in enum_peek.fields_for_serialize() {
313 if !first {
314 write!(writer, ",")?;
315 }
316 first = false;
317
318 write_json_string(writer, field.name)?;
319 write!(writer, ":")?;
320 serialize(&field_peek, writer)?;
321 }
322
323 write!(writer, "}}")?
324 } else {
325 if crate::variant_is_transparent(variant) {
329 let field = enum_peek.field(0).ok_or_else(|| {
330 io::Error::new(io::ErrorKind::Other, "Failed to access enum field")
331 })?;
332 serialize(&field, writer)?;
333 } else {
334 write!(writer, "[")?;
335
336 let mut first = true;
337 for (_field, field_peek) in enum_peek.fields_for_serialize() {
338 if !first {
339 write!(writer, ",")?;
340 }
341 first = false;
342 serialize(&field_peek, writer)?;
343 }
344
345 write!(writer, "]")?;
346 }
347 }
348
349 write!(writer, "}}")?;
350 Ok(())
351 }
352}
353
354fn serialize_option<W: Write>(peek: &Peek<'_, '_>, writer: &mut W) -> io::Result<()> {
356 let option_peek = peek
357 .into_option()
358 .map_err(|e| io::Error::new(io::ErrorKind::Other, format!("Not an option: {}", e)))?;
359
360 if option_peek.is_none() {
361 write!(writer, "null")
362 } else {
363 let value = option_peek
364 .value()
365 .ok_or_else(|| io::Error::new(io::ErrorKind::Other, "Failed to get option value"))?;
366 serialize(&value, writer)
367 }
368}
369
370fn write_json_string<W: Write>(writer: &mut W, s: &str) -> io::Result<()> {
372 write!(writer, "\"")?;
373
374 for c in s.chars() {
375 match c {
376 '"' => write!(writer, "\\\"")?,
377 '\\' => write!(writer, "\\\\")?,
378 '\n' => write!(writer, "\\n")?,
379 '\r' => write!(writer, "\\r")?,
380 '\t' => write!(writer, "\\t")?,
381 '\u{08}' => write!(writer, "\\b")?,
382 '\u{0C}' => write!(writer, "\\f")?,
383 c if c.is_control() => write!(writer, "\\u{:04x}", c as u32)?,
384 c => write!(writer, "{}", c)?,
385 }
386 }
387
388 write!(writer, "\"")
389}