1use facet_core::{Def, Facet, StructKind, Type, UserType};
2use facet_reflect::{HasFields, Peek, ScalarType};
3use std::io::{self, Write};
4
5pub fn to_string<'facet, T: Facet<'facet>>(value: &'facet T) -> String {
7 let peek = Peek::new(value);
8 let mut output = Vec::new();
9 let mut serializer = CsvSerializer::new(&mut output);
10 serialize_value(peek, &mut serializer).unwrap();
11 String::from_utf8(output).unwrap()
12}
13
14pub fn peek_to_string<'facet>(peek: Peek<'_, 'facet>) -> String {
16 let mut output = Vec::new();
17 let mut serializer = CsvSerializer::new(&mut output);
18 serialize_value(peek, &mut serializer).unwrap();
19 String::from_utf8(output).unwrap()
20}
21
22pub fn to_writer<'a, T: Facet<'a>, W: Write>(value: &'a T, writer: &mut W) -> io::Result<()> {
24 let peek = Peek::new(value);
25 let mut serializer = CsvSerializer::new(writer);
26 serialize_value(peek, &mut serializer)
27}
28
29pub fn peek_to_writer<'facet, W: Write>(peek: Peek<'_, 'facet>, writer: &mut W) -> io::Result<()> {
31 let mut serializer = CsvSerializer::new(writer);
32 serialize_value(peek, &mut serializer)
33}
34
35pub struct CsvSerializer<W> {
37 writer: W,
39
40 pos: usize,
42
43 n_fields: usize,
45
46 delim: &'static [u8],
48
49 newline: &'static [u8],
51}
52
53impl<W> CsvSerializer<W>
54where
55 W: Write,
56{
57 pub fn new(writer: W) -> Self {
59 Self {
60 writer,
61 pos: 0,
62 n_fields: 0,
63 delim: b",",
64 newline: b"\n",
65 }
66 }
67
68 fn set_n_fields(&mut self, n_fields: usize) {
69 self.n_fields = n_fields;
70 }
71
72 fn start_value(&mut self) -> Result<(), io::Error> {
74 if self.pos == 0 {
75 Ok(())
77 } else {
78 self.writer.write_all(self.delim)
79 }
80 }
81
82 fn end_value(&mut self) -> Result<(), io::Error> {
84 if self.pos == self.n_fields - 1 {
85 self.pos = 0;
87 self.writer.write_all(self.newline)
88 } else {
89 self.pos += 1;
91 Ok(())
93 }
94 }
95
96 fn write_empty(&mut self) -> io::Result<()> {
97 self.start_value()?;
98 self.end_value()
99 }
100}
101
102fn serialize_value<W: Write>(peek: Peek<'_, '_>, ser: &mut CsvSerializer<W>) -> io::Result<()> {
103 match (peek.shape().def, peek.shape().ty) {
104 (Def::Scalar, _) => {
105 let peek = peek.innermost_peek();
106 serialize_scalar(peek, ser)
107 }
108 (Def::Option(_), _) => {
109 let opt = peek.into_option().unwrap();
110 if let Some(inner) = opt.value() {
111 serialize_value(inner, ser)
112 } else {
113 ser.write_empty()
114 }
115 }
116 (Def::Pointer(_), _) => {
117 let ptr = peek.into_pointer().unwrap();
118 if let Some(inner) = ptr.borrow_inner() {
119 serialize_value(inner, ser)
120 } else {
121 ser.write_empty()
122 }
123 }
124 (_, Type::User(UserType::Struct(sd))) => {
125 match sd.kind {
126 StructKind::Unit => {
127 ser.write_empty()
129 }
130 StructKind::Tuple | StructKind::TupleStruct | StructKind::Struct => {
131 let ps = peek.into_struct().unwrap();
132 let fields: Vec<_> = ps.fields_for_serialize().collect();
133 ser.set_n_fields(fields.len());
134 for (_, field_value) in fields {
135 serialize_value(field_value, ser)?;
136 }
137 Ok(())
138 }
139 }
140 }
141 (_, Type::User(UserType::Enum(_))) => {
142 ser.write_empty()
144 }
145 (_, Type::Pointer(_)) => {
146 if let Some(s) = peek.as_str() {
148 ser.start_value()?;
149 write!(ser.writer, "{s}")?;
150 ser.end_value()
151 } else {
152 let innermost = peek.innermost_peek();
153 if innermost.shape() != peek.shape() {
154 serialize_value(innermost, ser)
155 } else {
156 ser.write_empty()
157 }
158 }
159 }
160 _ => {
161 ser.write_empty()
163 }
164 }
165}
166
167fn serialize_scalar<W: Write>(peek: Peek<'_, '_>, ser: &mut CsvSerializer<W>) -> io::Result<()> {
168 match peek.scalar_type() {
169 Some(ScalarType::Unit) => ser.write_empty(),
170 Some(ScalarType::Bool) => {
171 let v = *peek.get::<bool>().unwrap();
172 ser.start_value()?;
173 write!(ser.writer, "{}", if v { "true" } else { "false" })?;
174 ser.end_value()
175 }
176 Some(ScalarType::Char) => {
177 let c = *peek.get::<char>().unwrap();
178 ser.start_value()?;
179 write!(ser.writer, "{c}")?;
180 ser.end_value()
181 }
182 Some(ScalarType::Str) => {
183 let s = peek.get::<str>().unwrap();
184 ser.start_value()?;
185 write!(ser.writer, "{s}")?;
186 ser.end_value()
187 }
188 Some(ScalarType::String) => {
189 let s = peek.get::<String>().unwrap();
190 ser.start_value()?;
191 write!(ser.writer, "{s}")?;
192 ser.end_value()
193 }
194 Some(ScalarType::CowStr) => {
195 let s = peek.get::<alloc::borrow::Cow<'_, str>>().unwrap();
196 ser.start_value()?;
197 write!(ser.writer, "{s}")?;
198 ser.end_value()
199 }
200 Some(ScalarType::F32) => {
201 let v = *peek.get::<f32>().unwrap();
202 ser.start_value()?;
203 write!(ser.writer, "{v}")?;
204 ser.end_value()
205 }
206 Some(ScalarType::F64) => {
207 let v = *peek.get::<f64>().unwrap();
208 ser.start_value()?;
209 write!(ser.writer, "{v}")?;
210 ser.end_value()
211 }
212 Some(ScalarType::U8) => {
213 let v = *peek.get::<u8>().unwrap();
214 ser.start_value()?;
215 write!(ser.writer, "{v}")?;
216 ser.end_value()
217 }
218 Some(ScalarType::U16) => {
219 let v = *peek.get::<u16>().unwrap();
220 ser.start_value()?;
221 write!(ser.writer, "{v}")?;
222 ser.end_value()
223 }
224 Some(ScalarType::U32) => {
225 let v = *peek.get::<u32>().unwrap();
226 ser.start_value()?;
227 write!(ser.writer, "{v}")?;
228 ser.end_value()
229 }
230 Some(ScalarType::U64) => {
231 let v = *peek.get::<u64>().unwrap();
232 ser.start_value()?;
233 write!(ser.writer, "{v}")?;
234 ser.end_value()
235 }
236 Some(ScalarType::U128) => {
237 let v = *peek.get::<u128>().unwrap();
238 ser.start_value()?;
239 write!(ser.writer, "{v}")?;
240 ser.end_value()
241 }
242 Some(ScalarType::USize) => {
243 let v = *peek.get::<usize>().unwrap();
244 ser.start_value()?;
245 write!(ser.writer, "{v}")?;
246 ser.end_value()
247 }
248 Some(ScalarType::I8) => {
249 let v = *peek.get::<i8>().unwrap();
250 ser.start_value()?;
251 write!(ser.writer, "{v}")?;
252 ser.end_value()
253 }
254 Some(ScalarType::I16) => {
255 let v = *peek.get::<i16>().unwrap();
256 ser.start_value()?;
257 write!(ser.writer, "{v}")?;
258 ser.end_value()
259 }
260 Some(ScalarType::I32) => {
261 let v = *peek.get::<i32>().unwrap();
262 ser.start_value()?;
263 write!(ser.writer, "{v}")?;
264 ser.end_value()
265 }
266 Some(ScalarType::I64) => {
267 let v = *peek.get::<i64>().unwrap();
268 ser.start_value()?;
269 write!(ser.writer, "{v}")?;
270 ser.end_value()
271 }
272 Some(ScalarType::I128) => {
273 let v = *peek.get::<i128>().unwrap();
274 ser.start_value()?;
275 write!(ser.writer, "{v}")?;
276 ser.end_value()
277 }
278 Some(ScalarType::ISize) => {
279 let v = *peek.get::<isize>().unwrap();
280 ser.start_value()?;
281 write!(ser.writer, "{v}")?;
282 ser.end_value()
283 }
284 Some(_) | None => {
285 ser.start_value()?;
287 write!(ser.writer, "{peek}")?;
288 ser.end_value()
289 }
290 }
291}