Skip to main content

libconfig/
ser.rs

1//! Serializer for libconfig format
2
3use serde::{Serialize, ser};
4
5use crate::error::{Error, Result};
6
7/// A structure for serializing Rust values into libconfig format
8pub struct Serializer {
9    output: String,
10    indent_level: usize,
11    indent_size: usize,
12}
13
14impl Serializer {
15    fn new() -> Self {
16        Serializer {
17            output: String::new(),
18            indent_level: 0,
19            indent_size: 2,
20        }
21    }
22
23    fn indent(&mut self) {
24        self.indent_level += 1;
25    }
26
27    fn dedent(&mut self) {
28        self.indent_level = self.indent_level.saturating_sub(1);
29    }
30
31    fn write_indent(&mut self) {
32        for _ in 0..(self.indent_level * self.indent_size) {
33            self.output.push(' ');
34        }
35    }
36}
37
38/// Serialize the given value into a libconfig string
39pub fn to_string<T>(value: &T) -> Result<String>
40where
41    T: Serialize,
42{
43    let mut serializer = Serializer::new();
44    value.serialize(&mut serializer)?;
45    Ok(serializer.output)
46}
47
48impl<'a> ser::Serializer for &'a mut Serializer {
49    type Ok = ();
50    type Error = Error;
51
52    type SerializeSeq = Self;
53    type SerializeTuple = Self;
54    type SerializeTupleStruct = Self;
55    type SerializeTupleVariant = Self;
56    type SerializeMap = Self;
57    type SerializeStruct = Self;
58    type SerializeStructVariant = Self;
59
60    fn serialize_bool(self, v: bool) -> Result<()> {
61        self.output += if v { "true" } else { "false" };
62        Ok(())
63    }
64
65    fn serialize_i8(self, v: i8) -> Result<()> {
66        self.serialize_i32(i32::from(v))
67    }
68
69    fn serialize_i16(self, v: i16) -> Result<()> {
70        self.serialize_i32(i32::from(v))
71    }
72
73    fn serialize_i32(self, v: i32) -> Result<()> {
74        self.output += &v.to_string();
75        Ok(())
76    }
77
78    fn serialize_i64(self, v: i64) -> Result<()> {
79        self.output += &v.to_string();
80        self.output += "L";
81        Ok(())
82    }
83
84    fn serialize_u8(self, v: u8) -> Result<()> {
85        self.serialize_u32(u32::from(v))
86    }
87
88    fn serialize_u16(self, v: u16) -> Result<()> {
89        self.serialize_u32(u32::from(v))
90    }
91
92    fn serialize_u32(self, v: u32) -> Result<()> {
93        self.output += &v.to_string();
94        Ok(())
95    }
96
97    fn serialize_u64(self, v: u64) -> Result<()> {
98        self.output += &v.to_string();
99        self.output += "L";
100        Ok(())
101    }
102
103    fn serialize_f32(self, v: f32) -> Result<()> {
104        self.serialize_f64(f64::from(v))
105    }
106
107    fn serialize_f64(self, v: f64) -> Result<()> {
108        let s = v.to_string();
109        self.output += &s;
110        // Ensure float always has a decimal point to distinguish from integer
111        if !s.contains('.') && !s.contains('e') && !s.contains('E') {
112            self.output += ".0";
113        }
114        Ok(())
115    }
116
117    fn serialize_char(self, v: char) -> Result<()> {
118        self.serialize_str(&v.to_string())
119    }
120
121    fn serialize_str(self, v: &str) -> Result<()> {
122        self.output.push('"');
123        for ch in v.chars() {
124            match ch {
125                '"' => self.output.push_str("\\\""),
126                '\\' => self.output.push_str("\\\\"),
127                '\n' => self.output.push_str("\\n"),
128                '\r' => self.output.push_str("\\r"),
129                '\t' => self.output.push_str("\\t"),
130                '\x0C' => self.output.push_str("\\f"),
131                '\x08' => self.output.push_str("\\b"),
132                '\x0B' => self.output.push_str("\\v"),
133                '\x07' => self.output.push_str("\\a"),
134                _ => self.output.push(ch),
135            }
136        }
137        self.output.push('"');
138        Ok(())
139    }
140
141    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
142        use ser::SerializeSeq;
143        let mut seq = self.serialize_seq(Some(v.len()))?;
144        for byte in v {
145            seq.serialize_element(byte)?;
146        }
147        seq.end()
148    }
149
150    fn serialize_none(self) -> Result<()> {
151        Err(Error::TypeNotSupported("Option::None".to_string()))
152    }
153
154    fn serialize_some<T>(self, value: &T) -> Result<()>
155    where
156        T: ?Sized + Serialize,
157    {
158        value.serialize(self)
159    }
160
161    fn serialize_unit(self) -> Result<()> {
162        Err(Error::UnitNotSupported)
163    }
164
165    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
166        self.serialize_unit()
167    }
168
169    fn serialize_unit_variant(
170        self,
171        _name: &'static str,
172        _variant_index: u32,
173        variant: &'static str,
174    ) -> Result<()> {
175        self.serialize_str(variant)
176    }
177
178    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
179    where
180        T: ?Sized + Serialize,
181    {
182        value.serialize(self)
183    }
184
185    fn serialize_newtype_variant<T>(
186        self,
187        _name: &'static str,
188        _variant_index: u32,
189        variant: &'static str,
190        value: &T,
191    ) -> Result<()>
192    where
193        T: ?Sized + Serialize,
194    {
195        self.output += variant;
196        self.output += " = ";
197        value.serialize(&mut *self)?;
198        Ok(())
199    }
200
201    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
202        self.output.push('[');
203        Ok(self)
204    }
205
206    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
207        self.output.push('(');
208        Ok(self)
209    }
210
211    fn serialize_tuple_struct(
212        self,
213        _name: &'static str,
214        _len: usize,
215    ) -> Result<Self::SerializeTupleStruct> {
216        self.output.push('(');
217        Ok(self)
218    }
219
220    fn serialize_tuple_variant(
221        self,
222        _name: &'static str,
223        _variant_index: u32,
224        variant: &'static str,
225        _len: usize,
226    ) -> Result<Self::SerializeTupleVariant> {
227        self.output += variant;
228        self.output += " = (";
229        Ok(self)
230    }
231
232    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
233        self.output.push('{');
234        self.indent();
235        Ok(self)
236    }
237
238    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
239        self.serialize_map(Some(len))
240    }
241
242    fn serialize_struct_variant(
243        self,
244        _name: &'static str,
245        _variant_index: u32,
246        variant: &'static str,
247        _len: usize,
248    ) -> Result<Self::SerializeStructVariant> {
249        self.output += variant;
250        self.output += " = {";
251        self.indent();
252        Ok(self)
253    }
254}
255
256impl<'a> ser::SerializeSeq for &'a mut Serializer {
257    type Ok = ();
258    type Error = Error;
259
260    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
261    where
262        T: ?Sized + Serialize,
263    {
264        if !self.output.ends_with('[') {
265            self.output += ", ";
266        }
267        value.serialize(&mut **self)
268    }
269
270    fn end(self) -> Result<()> {
271        self.output.push(']');
272        Ok(())
273    }
274}
275
276impl<'a> ser::SerializeTuple for &'a mut Serializer {
277    type Ok = ();
278    type Error = Error;
279
280    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
281    where
282        T: ?Sized + Serialize,
283    {
284        if !self.output.ends_with('(') {
285            self.output += ", ";
286        }
287        value.serialize(&mut **self)
288    }
289
290    fn end(self) -> Result<()> {
291        self.output.push(')');
292        Ok(())
293    }
294}
295
296impl<'a> ser::SerializeTupleStruct for &'a mut Serializer {
297    type Ok = ();
298    type Error = Error;
299
300    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
301    where
302        T: ?Sized + Serialize,
303    {
304        if !self.output.ends_with('(') {
305            self.output += ", ";
306        }
307        value.serialize(&mut **self)
308    }
309
310    fn end(self) -> Result<()> {
311        self.output.push(')');
312        Ok(())
313    }
314}
315
316impl<'a> ser::SerializeTupleVariant for &'a mut Serializer {
317    type Ok = ();
318    type Error = Error;
319
320    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
321    where
322        T: ?Sized + Serialize,
323    {
324        if !self.output.ends_with('(') {
325            self.output += ", ";
326        }
327        value.serialize(&mut **self)
328    }
329
330    fn end(self) -> Result<()> {
331        self.output.push(')');
332        Ok(())
333    }
334}
335
336impl<'a> ser::SerializeMap for &'a mut Serializer {
337    type Ok = ();
338    type Error = Error;
339
340    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
341    where
342        T: ?Sized + Serialize,
343    {
344        if !self.output.ends_with('{') {
345            self.output.push(';');
346        }
347        self.output.push('\n');
348        self.write_indent();
349        // Validate key is a string, then write as bare identifier (not quoted)
350        let mut key_capture = KeyCapture { key: String::new() };
351        key.serialize(&mut key_capture)?;
352        self.output += &key_capture.key;
353        Ok(())
354    }
355
356    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
357    where
358        T: ?Sized + Serialize,
359    {
360        self.output += " = ";
361        value.serialize(&mut **self)
362    }
363
364    fn end(self) -> Result<()> {
365        self.dedent();
366        if !self.output.ends_with('{') {
367            self.output.push(';');
368        }
369        self.output.push('\n');
370        self.write_indent();
371        self.output.push('}');
372        Ok(())
373    }
374}
375
376impl<'a> ser::SerializeStruct for &'a mut Serializer {
377    type Ok = ();
378    type Error = Error;
379
380    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
381    where
382        T: ?Sized + Serialize,
383    {
384        if !self.output.ends_with('{') {
385            self.output.push(';');
386        }
387        self.output.push('\n');
388        self.write_indent();
389        self.output += key;
390        self.output += " = ";
391        value.serialize(&mut **self)
392    }
393
394    fn end(self) -> Result<()> {
395        self.dedent();
396        if !self.output.ends_with('{') {
397            self.output.push(';');
398        }
399        self.output.push('\n');
400        self.write_indent();
401        self.output.push('}');
402        Ok(())
403    }
404}
405
406impl<'a> ser::SerializeStructVariant for &'a mut Serializer {
407    type Ok = ();
408    type Error = Error;
409
410    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
411    where
412        T: ?Sized + Serialize,
413    {
414        if !self.output.ends_with('{') {
415            self.output.push(';');
416        }
417        self.output.push('\n');
418        self.write_indent();
419        self.output += key;
420        self.output += " = ";
421        value.serialize(&mut **self)
422    }
423
424    fn end(self) -> Result<()> {
425        self.dedent();
426        if !self.output.ends_with('{') {
427            self.output.push(';');
428        }
429        self.output.push('\n');
430        self.write_indent();
431        self.output.push('}');
432        Ok(())
433    }
434}
435
436// Helper serializer to capture map keys as bare identifier strings
437struct KeyCapture {
438    key: String,
439}
440
441impl<'a> ser::Serializer for &'a mut KeyCapture {
442    type Ok = ();
443    type Error = Error;
444
445    type SerializeSeq = ser::Impossible<(), Error>;
446    type SerializeTuple = ser::Impossible<(), Error>;
447    type SerializeTupleStruct = ser::Impossible<(), Error>;
448    type SerializeTupleVariant = ser::Impossible<(), Error>;
449    type SerializeMap = ser::Impossible<(), Error>;
450    type SerializeStruct = ser::Impossible<(), Error>;
451    type SerializeStructVariant = ser::Impossible<(), Error>;
452
453    fn serialize_str(self, v: &str) -> Result<()> {
454        self.key = v.to_string();
455        Ok(())
456    }
457
458    fn serialize_unit_variant(
459        self,
460        _name: &'static str,
461        _variant_index: u32,
462        variant: &'static str,
463    ) -> Result<()> {
464        self.key = variant.to_string();
465        Ok(())
466    }
467
468    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
469    where
470        T: ?Sized + Serialize,
471    {
472        value.serialize(self)
473    }
474
475    fn serialize_bool(self, _v: bool) -> Result<()> {
476        Err(Error::KeyMustBeAString)
477    }
478
479    fn serialize_i8(self, _v: i8) -> Result<()> {
480        Err(Error::KeyMustBeAString)
481    }
482
483    fn serialize_i16(self, _v: i16) -> Result<()> {
484        Err(Error::KeyMustBeAString)
485    }
486
487    fn serialize_i32(self, _v: i32) -> Result<()> {
488        Err(Error::KeyMustBeAString)
489    }
490
491    fn serialize_i64(self, _v: i64) -> Result<()> {
492        Err(Error::KeyMustBeAString)
493    }
494
495    fn serialize_u8(self, _v: u8) -> Result<()> {
496        Err(Error::KeyMustBeAString)
497    }
498
499    fn serialize_u16(self, _v: u16) -> Result<()> {
500        Err(Error::KeyMustBeAString)
501    }
502
503    fn serialize_u32(self, _v: u32) -> Result<()> {
504        Err(Error::KeyMustBeAString)
505    }
506
507    fn serialize_u64(self, _v: u64) -> Result<()> {
508        Err(Error::KeyMustBeAString)
509    }
510
511    fn serialize_f32(self, _v: f32) -> Result<()> {
512        Err(Error::KeyMustBeAString)
513    }
514
515    fn serialize_f64(self, _v: f64) -> Result<()> {
516        Err(Error::KeyMustBeAString)
517    }
518
519    fn serialize_char(self, _v: char) -> Result<()> {
520        Err(Error::KeyMustBeAString)
521    }
522
523    fn serialize_bytes(self, _v: &[u8]) -> Result<()> {
524        Err(Error::KeyMustBeAString)
525    }
526
527    fn serialize_none(self) -> Result<()> {
528        Err(Error::KeyMustBeAString)
529    }
530
531    fn serialize_some<T>(self, _value: &T) -> Result<()>
532    where
533        T: ?Sized + Serialize,
534    {
535        Err(Error::KeyMustBeAString)
536    }
537
538    fn serialize_unit(self) -> Result<()> {
539        Err(Error::KeyMustBeAString)
540    }
541
542    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
543        Err(Error::KeyMustBeAString)
544    }
545
546    fn serialize_newtype_variant<T>(
547        self,
548        _name: &'static str,
549        _variant_index: u32,
550        _variant: &'static str,
551        _value: &T,
552    ) -> Result<()>
553    where
554        T: ?Sized + Serialize,
555    {
556        Err(Error::KeyMustBeAString)
557    }
558
559    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
560        Err(Error::KeyMustBeAString)
561    }
562
563    fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple> {
564        Err(Error::KeyMustBeAString)
565    }
566
567    fn serialize_tuple_struct(
568        self,
569        _name: &'static str,
570        _len: usize,
571    ) -> Result<Self::SerializeTupleStruct> {
572        Err(Error::KeyMustBeAString)
573    }
574
575    fn serialize_tuple_variant(
576        self,
577        _name: &'static str,
578        _variant_index: u32,
579        _variant: &'static str,
580        _len: usize,
581    ) -> Result<Self::SerializeTupleVariant> {
582        Err(Error::KeyMustBeAString)
583    }
584
585    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
586        Err(Error::KeyMustBeAString)
587    }
588
589    fn serialize_struct(self, _name: &'static str, _len: usize) -> Result<Self::SerializeStruct> {
590        Err(Error::KeyMustBeAString)
591    }
592
593    fn serialize_struct_variant(
594        self,
595        _name: &'static str,
596        _variant_index: u32,
597        _variant: &'static str,
598        _len: usize,
599    ) -> Result<Self::SerializeStructVariant> {
600        Err(Error::KeyMustBeAString)
601    }
602}
603
604#[cfg(test)]
605mod tests {
606    use super::*;
607    use serde::Serialize;
608
609    #[test]
610    fn test_serialize_primitives() {
611        assert_eq!(to_string(&42u32).unwrap(), "42");
612        assert_eq!(to_string(&42i64).unwrap(), "42L");
613        assert_eq!(to_string(&3.14f64).unwrap(), "3.14");
614        assert_eq!(to_string(&true).unwrap(), "true");
615        assert_eq!(to_string(&"hello".to_string()).unwrap(), "\"hello\"");
616    }
617
618    #[test]
619    fn test_serialize_array() {
620        let arr = vec![1, 2, 3];
621        assert_eq!(to_string(&arr).unwrap(), "[1, 2, 3]");
622    }
623
624    #[test]
625    fn test_serialize_struct() {
626        #[derive(Serialize)]
627        struct Test {
628            a: i32,
629            b: String,
630        }
631
632        let test = Test {
633            a: 42,
634            b: "hello".to_string(),
635        };
636        let result = to_string(&test).unwrap();
637        assert!(result.contains("a = 42"));
638        assert!(result.contains("b = \"hello\""));
639    }
640
641    #[test]
642    fn test_serialize_i8_no_l_suffix() {
643        assert_eq!(to_string(&42i8).unwrap(), "42");
644        assert_eq!(to_string(&42i16).unwrap(), "42");
645        assert_eq!(to_string(&42i32).unwrap(), "42");
646        assert_eq!(to_string(&42i64).unwrap(), "42L");
647    }
648
649    #[test]
650    fn test_serialize_u64_has_l_suffix() {
651        assert_eq!(to_string(&42u8).unwrap(), "42");
652        assert_eq!(to_string(&42u16).unwrap(), "42");
653        assert_eq!(to_string(&42u32).unwrap(), "42");
654        assert_eq!(to_string(&42u64).unwrap(), "42L");
655    }
656
657    #[test]
658    fn test_serialize_float_always_has_decimal() {
659        // 1.0f64.to_string() is "1" in Rust - we must add ".0"
660        assert_eq!(to_string(&1.0f64).unwrap(), "1.0");
661        assert_eq!(to_string(&0.0f64).unwrap(), "0.0");
662        // Already has decimal
663        assert_eq!(to_string(&3.14f64).unwrap(), "3.14");
664    }
665
666    #[test]
667    fn test_serialize_tuple_as_list() {
668        let tup = (1, 2, 3);
669        assert_eq!(to_string(&tup).unwrap(), "(1, 2, 3)");
670    }
671
672    #[test]
673    fn test_serialize_map_bare_keys() {
674        use indexmap::IndexMap;
675        let mut map = IndexMap::new();
676        map.insert("key".to_string(), 42i32);
677        let result = to_string(&map).unwrap();
678        // Keys should be bare identifiers, not quoted
679        assert!(result.contains("key = 42"));
680        assert!(!result.contains("\"key\""));
681    }
682}