1use serde::{ser, Serialize};
2use smol_str::{SmolStr, SmolStrBuilder};
3
4use crate::{
5 error::{Error, Result},
6 is_alnum_strict, is_numeric,
7};
8
9pub struct Serializer {
10 output: Vec<SmolStr>,
11 seq_stack: Vec<SeqState>,
13 map_depth: usize,
15}
16
17struct SeqState {
18 elements: Vec<Vec<SmolStr>>, all_simple: bool,
20 all_numeric: bool, }
22
23macro_rules! forward_to {
24 ($method_from: ident, $t: ty, $method_to:ident, $conversion:expr) => {
25 fn $method_from(self, v: $t) -> Result<()> {
26 self.$method_to($conversion(v))
27 }
28 };
29}
30
31const FLOAT_PRECISION: i32 = 4;
32
33pub fn to_string<T>(value: &T) -> Result<String>
34where
35 T: Serialize,
36{
37 let mut serializer = Serializer {
38 output: Vec::new(),
39 seq_stack: Vec::new(),
40 map_depth: 0,
41 };
42 value.serialize(&mut serializer)?;
43 Ok(serializer.output.join(""))
44}
45
46impl ser::Serializer for &mut Serializer {
47 type Ok = ();
48 type Error = Error;
49 type SerializeSeq = Self;
50 type SerializeTuple = Self;
51 type SerializeTupleStruct = Self;
52 type SerializeTupleVariant = Self;
53 type SerializeMap = Self;
54 type SerializeStruct = Self;
55 type SerializeStructVariant = Self;
56
57 fn serialize_bool(self, v: bool) -> Result<()> {
58 self.output
59 .push(SmolStr::new_static(if v { "1" } else { "0" }));
60 Ok(())
61 }
62 forward_to!(serialize_i8, i8, serialize_i64, i64::from);
63 forward_to!(serialize_i16, i16, serialize_i64, i64::from);
64 forward_to!(serialize_i32, i32, serialize_i64, i64::from);
65 forward_to!(serialize_u8, u8, serialize_u64, u64::from);
66 forward_to!(serialize_u16, u16, serialize_u64, u64::from);
67 forward_to!(serialize_u32, u32, serialize_u64, u64::from);
68
69 fn serialize_i64(self, v: i64) -> Result<()> {
70 self.output.push(SmolStr::new(format!("{v}")));
71 Ok(())
72 }
73
74 fn serialize_u64(self, v: u64) -> Result<()> {
75 self.output.push(SmolStr::new(format!("{v}")));
76 Ok(())
77 }
78
79 forward_to!(serialize_f32, f32, serialize_f64, f64::from);
80
81 fn serialize_f64(self, v: f64) -> Result<()> {
82 self.output.push(SmolStr::new(format!(
83 "{}",
84 (v * 10_f64.powi(FLOAT_PRECISION)).round() / 10_f64.powi(FLOAT_PRECISION)
85 )));
86 Ok(())
87 }
88
89 fn serialize_char(self, v: char) -> Result<()> {
90 self.output.push(SmolStr::new_inline(&format!("{v}")));
91 Ok(())
92 }
93
94 fn serialize_str(self, v: &str) -> Result<()> {
95 escape_string(&mut self.output, v);
96 Ok(())
97 }
98
99 fn serialize_bytes(self, data: &[u8]) -> Result<()> {
100 let mut builder = SmolStrBuilder::new();
101 builder.push('<');
102 for byte in data {
103 let [one, two] = hex_digits_for_byte(*byte);
104 builder.push(one);
105 builder.push(two);
106 }
107 builder.push('>');
108 self.output.push(builder.finish());
109 Ok(())
110 }
111
112 fn serialize_none(self) -> Result<()> {
113 self.serialize_unit()
114 }
115
116 fn serialize_some<T>(self, value: &T) -> Result<()>
117 where
118 T: ?Sized + Serialize,
119 {
120 value.serialize(self)
121 }
122
123 fn serialize_unit(self) -> Result<()> {
124 self.output.push(SmolStr::new_static("null"));
126 Ok(())
127 }
128
129 fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
130 self.serialize_unit()
131 }
132
133 fn serialize_unit_variant(
134 self,
135 _name: &'static str,
136 _variant_index: u32,
137 variant: &'static str,
138 ) -> Result<()> {
139 self.serialize_str(variant)
140 }
141
142 fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
143 where
144 T: ?Sized + Serialize,
145 {
146 value.serialize(self)
147 }
148
149 fn serialize_newtype_variant<T>(
150 self,
151 _name: &'static str,
152 _variant_index: u32,
153 variant: &'static str,
154 value: &T,
155 ) -> Result<()>
156 where
157 T: ?Sized + Serialize,
158 {
159 self.output.push(SmolStr::new_static("{newtype"));
160 variant.serialize(&mut *self)?;
161 self.output.push(SmolStr::new_static(" = "));
162 value.serialize(&mut *self)?;
163 self.output.push(SmolStr::new_static(";}"));
164 Ok(())
165 }
166
167 fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
168 self.seq_stack.push(SeqState {
169 elements: Vec::new(),
170 all_simple: true,
171 all_numeric: true,
172 });
173 Ok(self)
174 }
175
176 fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
177 self.output.push(SmolStr::new_static("("));
178 Ok(self)
179 }
180
181 fn serialize_tuple_struct(
183 self,
184 _name: &'static str,
185 len: usize,
186 ) -> Result<Self::SerializeTupleStruct> {
187 self.serialize_seq(Some(len))
188 }
189
190 fn serialize_tuple_variant(
191 self,
192 _name: &'static str,
193 _variant_index: u32,
194 variant: &'static str,
195 _len: usize,
196 ) -> Result<Self::SerializeTupleVariant> {
197 self.output.push(SmolStr::new_static("{tuplevariant"));
198 variant.serialize(&mut *self)?;
199 self.output.push(SmolStr::new_static(" = ("));
200 Ok(self)
201 }
202
203 fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
204 self.map_depth += 1;
205 self.output.push(SmolStr::new_static("{"));
206 Ok(self)
207 }
208
209 fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
210 self.serialize_map(Some(len))
211 }
212
213 fn serialize_struct_variant(
214 self,
215 _name: &'static str,
216 _variant_index: u32,
217 variant: &'static str,
218 _len: usize,
219 ) -> Result<Self::SerializeStructVariant> {
220 self.output.push(SmolStr::new_static("{structvariant"));
221 variant.serialize(&mut *self)?;
222 self.output.push(SmolStr::new_static(" = }"));
223 Ok(self)
224 }
225}
226
227impl ser::SerializeSeq for &mut Serializer {
228 type Ok = ();
230 type Error = Error;
232
233 fn serialize_element<T>(&mut self, value: &T) -> Result<()>
235 where
236 T: ?Sized + Serialize,
237 {
238 let mut tmp = Serializer {
240 output: Vec::new(),
241 seq_stack: Vec::new(),
242 map_depth: 0,
243 };
244 value.serialize(&mut tmp)?;
245 let complex = match tmp.output.first() {
247 Some(first) => {
248 let s = first.as_str();
249 s.starts_with("(\n") || s == "(" || s == "{"
250 }
251 None => false,
252 };
253 let all_numeric = tmp.output.iter().all(|tok| {
255 let s = tok.as_str();
256 s.parse::<f64>().is_ok() || s == "-" || s == "."
257 });
258 if let Some(state) = self.seq_stack.last_mut() {
259 if complex {
260 state.all_simple = false;
261 }
262 if !all_numeric {
263 state.all_numeric = false;
264 }
265 state.elements.push(tmp.output);
266 }
267 Ok(())
268 }
269
270 fn end(self) -> Result<()> {
272 if let Some(state) = self.seq_stack.pop() {
273 if state.all_simple {
274 self.output.push(SmolStr::new_static("("));
276 for (i, elem) in state.elements.iter().enumerate() {
277 if i > 0 {
278 if state.all_numeric {
280 self.output.push(SmolStr::new_static(","));
281 } else {
282 self.output.push(SmolStr::new_static(", "));
283 }
284 }
285 for tok in elem {
287 self.output.push(tok.clone());
288 }
289 }
290 self.output.push(SmolStr::new_static(")"));
291 } else {
292 self.output.push(SmolStr::new_static("(\n"));
294 for (i, elem) in state.elements.iter().enumerate() {
295 if i > 0 {
296 self.output.push(SmolStr::new_static(",\n"));
297 }
298 for tok in elem {
299 self.output.push(tok.clone());
300 }
301 }
302 self.output.push(SmolStr::new_static("\n)"));
303 }
304 Ok(())
307 } else {
308 Ok(())
310 }
311 }
312}
313
314impl ser::SerializeTuple for &mut Serializer {
317 type Ok = ();
318 type Error = Error;
319
320 fn serialize_element<T>(&mut self, value: &T) -> Result<()>
321 where
322 T: ?Sized + Serialize,
323 {
324 if !self.output.ends_with(&[SmolStr::new_static("(")]) {
325 self.output.push(SmolStr::new_static(","));
326 }
327 value.serialize(&mut **self)
328 }
329
330 fn end(self) -> Result<()> {
331 self.output.push(SmolStr::new_static(")"));
332 Ok(())
333 }
334}
335
336impl ser::SerializeTupleStruct for &mut Serializer {
338 type Ok = ();
339 type Error = Error;
340
341 fn serialize_field<T>(&mut self, value: &T) -> Result<()>
342 where
343 T: ?Sized + Serialize,
344 {
345 if !self.output.ends_with(&[SmolStr::new_static("(")]) {
346 self.output.push(SmolStr::new_static(", "));
347 }
348 value.serialize(&mut **self)
349 }
350
351 fn end(self) -> Result<()> {
352 self.output.push(SmolStr::new_static(")"));
353 Ok(())
354 }
355}
356
357impl ser::SerializeTupleVariant for &mut Serializer {
358 type Ok = ();
359 type Error = Error;
360
361 fn serialize_field<T>(&mut self, value: &T) -> Result<()>
362 where
363 T: ?Sized + Serialize,
364 {
365 if !self.output.ends_with(&[SmolStr::new_static("(")]) {
366 self.output.push(SmolStr::new_static(", "));
367 }
368 value.serialize(&mut **self)
369 }
370
371 fn end(self) -> Result<()> {
372 self.output.push(SmolStr::new_static(");}"));
373 Ok(())
374 }
375}
376
377impl ser::SerializeMap for &mut Serializer {
378 type Ok = ();
379 type Error = Error;
380
381 fn serialize_key<T>(&mut self, key: &T) -> Result<()>
382 where
383 T: ?Sized + Serialize,
384 {
385 self.output.push(SmolStr::new_static("\n"));
389 key.serialize(&mut **self)
390 }
391
392 fn serialize_value<T>(&mut self, value: &T) -> Result<()>
393 where
394 T: ?Sized + Serialize,
395 {
396 self.output.push(SmolStr::new_static(" = "));
397 value.serialize(&mut **self)?;
398 self.output.push(SmolStr::new_static(";"));
399 Ok(())
400 }
401
402 fn end(self) -> Result<()> {
403 self.output.push(SmolStr::new_static("\n}"));
404 self.map_depth = self.map_depth.saturating_sub(1);
407 Ok(())
408 }
409}
410
411impl ser::SerializeStruct for &mut Serializer {
412 type Ok = ();
413 type Error = Error;
414
415 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
416 where
417 T: ?Sized + Serialize,
418 {
419 self.output.push(SmolStr::new_static("\n"));
420 key.serialize(&mut **self)?;
421 self.output.push(SmolStr::new_static(" = "));
422 value.serialize(&mut **self)?;
423 self.output.push(SmolStr::new_static(";"));
424 Ok(())
425 }
426
427 fn end(self) -> Result<()> {
428 if self.output.last() == Some(&SmolStr::new_static(";")) {
429 self.output.pop();
430 self.output.push(SmolStr::new_static(";"));
431 }
432 self.output.push(SmolStr::new_static("\n}"));
433 Ok(())
434 }
435}
436
437impl ser::SerializeStructVariant for &mut Serializer {
438 type Ok = ();
439 type Error = Error;
440
441 fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
442 where
443 T: ?Sized + Serialize,
444 {
445 if !self.output.ends_with(&[SmolStr::new_static("{")]) {
446 self.output.push(SmolStr::new_static("; "));
447 }
448 key.serialize(&mut **self)?;
449 self.output.push(SmolStr::new_static(" = "));
450 value.serialize(&mut **self)
451 }
452
453 fn end(self) -> Result<()> {
454 self.output.push(SmolStr::new_static("};}"));
455 Ok(())
456 }
457}
458
459fn escape_string(buf: &mut Vec<SmolStr>, s: &str) {
460 if !s.is_empty()
461 && (s.as_bytes().iter().all(|&b| is_alnum_strict(b))
462 && !s.as_bytes().iter().all(|&b| is_numeric(b)))
463 {
464 buf.push(SmolStr::new(s));
465 } else {
466 buf.push(SmolStr::new_static("\""));
467 let mut start = 0;
468 let mut ix = start;
469 while ix < s.len() {
470 let b = s.as_bytes()[ix];
471 match b {
472 b'"' | b'\\' => {
473 buf.push(SmolStr::new(&s[start..ix]));
474 buf.push(SmolStr::new_static("\\"));
475 start = ix;
476 }
477 _ => (),
478 }
479 ix += 1;
480 }
481 buf.push(SmolStr::new(&s[start..]));
482 buf.push(SmolStr::new_static("\""));
483 }
484}
485
486#[inline]
487fn hex_digits_for_byte(byte: u8) -> [char; 2] {
488 fn to_hex_digit(val: u8) -> char {
489 match val {
490 0..=9 => ('0' as u32 as u8 + val).into(),
491 10..=15 => (('a' as u32 as u8) + val - 10).into(),
492 _ => unreachable!("only called with values in range 0..=15"),
493 }
494 }
495
496 [to_hex_digit(byte >> 4), to_hex_digit(byte & 0x0f)]
497}
498
499#[cfg(test)]
500mod tests {
501 use crate::Plist;
502
503 use super::*;
504
505 #[test]
506 fn hex_to_ascii() {
507 assert_eq!(hex_digits_for_byte(0x01), ['0', '1']);
508 assert_eq!(hex_digits_for_byte(0x00), ['0', '0']);
509 assert_eq!(hex_digits_for_byte(0xff), ['f', 'f']);
510 assert_eq!(hex_digits_for_byte(0xf0), ['f', '0']);
511 assert_eq!(hex_digits_for_byte(0x0f), ['0', 'f']);
512 }
513
514 #[test]
515 fn test_serialize() {
516 let plist: Plist = vec![
517 Plist::String("hello".to_string()),
518 Plist::String("world".to_string()),
519 ]
520 .into();
521 let s = to_string(&plist).unwrap();
522 assert_eq!(s, r#"(hello, world)"#);
523 }
524
525 #[test]
526 fn test_serialize_map() {
527 let plist_str = "{\nfoo = bar;\nhello = world;\ntuple = (1,2);\n}";
528 let plist: Plist = Plist::parse(plist_str).unwrap();
529 let s = to_string(&plist).unwrap();
530 assert_eq!(s, plist_str);
531 }
532
533 #[test]
534 fn test_serialize_struct() {
535 let plist_str = r#"
538{
539axes = (
540{
541hidden = 1;
542name = Weight;
543tag = wght;
544}
545);
546}"#
547 .trim(); let plist: Plist = Plist::parse(plist_str).unwrap();
549 let s = to_string(&plist).unwrap();
550 assert_eq!(s, plist_str);
551 }
552
553 #[test]
554 fn test_vec_axis() {
555 #[derive(Serialize, Debug, Default, Clone)]
556 struct Axis {
557 #[serde(default)]
559 pub hidden: bool,
560 pub name: String,
562 pub tag: String,
564 }
565 let foo = vec![Axis {
566 hidden: true,
567 name: "Weight".to_string(),
568 tag: "wght".to_string(),
569 }];
570 let s = to_string(&foo).unwrap();
571 let expected = "(\n{\nhidden = 1;\nname = Weight;\ntag = wght;\n}\n)";
574 assert_eq!(s, expected);
575 }
576
577 #[test]
578 fn test_string_escaping() {
579 let str = "files/LinkedFontv3.glyphs";
580 let mut buf = Vec::new();
581 escape_string(&mut buf, str);
582 let output = buf.join("");
583 assert_eq!(output, "\"files/LinkedFontv3.glyphs\"");
584 }
585}