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