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