1use std::{fs::File, path::Path};
2
3use serde::ser::Serialize as _;
4
5use super::error::{Error, Result};
6
7cfg_if::cfg_if! {
8    if #[cfg(feature = "debug")] {
9        use log::debug;
10    } else {
11        #[allow(unused_macros)]
12        macro_rules! debug {
13            ($fmt:expr $(, $arg:expr)*) => {};
14        }
15    }
16}
17
18pub struct Serializer {
20    output: String,
21    base_prefix: String,
22    prefix: String,
23    key: bool,
24    sequence: bool,
25    prefix_before: String,
26}
27
28impl Serializer {
29    fn new(prefix: Option<&str>) -> Self {
30        Self {
31            output: String::new(),
32            base_prefix: prefix.unwrap_or("").to_uppercase(),
33            prefix: "".into(),
34            key: false,
35            sequence: false,
36            prefix_before: "".into(),
37        }
38    }
39
40    pub(crate) fn strip_line_breaks(&mut self) {
41        while self.output.ends_with('\n') {
42            self.output = self.output[..self.output.len() - 1].into();
43        }
44    }
45}
46
47pub fn to_string<T>(v: &T) -> Result<String>
60where
61    T: serde::ser::Serialize,
62{
63    to_string_inner(None, v)
64}
65
66pub fn to_string_inner<T>(prefix: Option<&str>, v: &T) -> Result<String>
67where
68    T: serde::ser::Serialize,
69{
70    let mut serializer = Serializer::new(prefix);
71    v.serialize(&mut serializer)?;
72
73    Ok(serializer.output)
74}
75
76pub fn to_writer<W, T>(writer: W, v: &T) -> Result<()>
93where
94    W: std::io::Write,
95    T: serde::ser::Serialize,
96{
97    to_writer_inner(None, writer, v)
98}
99
100pub(crate) fn to_writer_inner<W, T>(prefix: Option<&str>, mut writer: W, v: &T) -> Result<()>
101where
102    W: std::io::Write,
103    T: serde::ser::Serialize,
104{
105    writer
106        .write_all(to_string_inner(prefix, v)?.as_bytes())
107        .map_err(Error::new)
108}
109
110pub fn to_file<P, T>(path: P, v: &T) -> Result<()>
124where
125    P: AsRef<Path>,
126    T: serde::ser::Serialize,
127{
128    to_file_inner(None, path, v)
129}
130
131pub fn to_file_inner<P, T>(prefix: Option<&str>, path: P, v: &T) -> Result<()>
132where
133    P: AsRef<Path>,
134    T: serde::ser::Serialize,
135{
136    let file = File::create(path).map_err(Error::new)?;
137    to_writer_inner(prefix, file, v)
138}
139
140impl serde::ser::Serializer for &mut Serializer {
141    type Ok = ();
142    type Error = Error;
143
144    type SerializeSeq = Self;
145    type SerializeTuple = Self;
146    type SerializeTupleStruct = Self;
147    type SerializeTupleVariant = Self;
148    type SerializeMap = Self;
149    type SerializeStruct = Self;
150    type SerializeStructVariant = Self;
151
152    fn serialize_bool(self, v: bool) -> Result<()> {
153        debug!("serialize bool: {}", v);
154        self.output += if v { "true" } else { "false" };
155        Ok(())
156    }
157
158    fn serialize_i8(self, v: i8) -> Result<()> {
159        debug!("serialize i8: {}", v);
160        self.serialize_i64(i64::from(v))
161    }
162
163    fn serialize_i16(self, v: i16) -> Result<()> {
164        debug!("serialize i16: {}", v);
165        self.serialize_i64(i64::from(v))
166    }
167
168    fn serialize_i32(self, v: i32) -> Result<()> {
169        debug!("serialize i32: {}", v);
170        self.serialize_i64(i64::from(v))
171    }
172
173    fn serialize_i64(self, v: i64) -> Result<()> {
174        debug!("serialize i64: {}", v);
175        self.output += &v.to_string();
176        Ok(())
177    }
178
179    fn serialize_u8(self, v: u8) -> Result<()> {
180        debug!("serialize u8: {}", v);
181        self.serialize_u64(u64::from(v))
182    }
183
184    fn serialize_u16(self, v: u16) -> Result<()> {
185        debug!("serialize u16: {}", v);
186        self.serialize_u64(u64::from(v))
187    }
188
189    fn serialize_u32(self, v: u32) -> Result<()> {
190        debug!("serialize u32: {}", v);
191        self.serialize_u64(u64::from(v))
192    }
193
194    fn serialize_u64(self, v: u64) -> Result<()> {
195        debug!("serialize u64: {}", v);
196        self.output += &v.to_string();
197        Ok(())
198    }
199
200    fn serialize_f32(self, v: f32) -> Result<()> {
201        debug!("serialize f32: {}", v);
202        self.serialize_f64(f64::from(v))
203    }
204
205    fn serialize_f64(self, v: f64) -> Result<()> {
206        debug!("serialize f64: {}", v);
207        self.output += &v.to_string();
208        Ok(())
209    }
210
211    fn serialize_char(self, v: char) -> Result<()> {
212        debug!("serialize char: {}", v);
213        self.serialize_str(&v.to_string())
214    }
215
216    fn serialize_str(self, v: &str) -> Result<()> {
217        debug!("serialize &str: {}", v);
218
219        if self.key {
220            let mut key = self.base_prefix.clone();
221            if !self.prefix.is_empty() {
222                self.prefix.push('_');
223            }
224            self.prefix += &v.to_uppercase();
225            key += &self.prefix;
226            if key.find(' ').is_some()
227                || key.find('#').is_some()
228                || key.find('\"').is_some()
229                || key.find('\'').is_some()
230            {
231                return Err(Error::Syntax);
232            }
233
234            self.output += &key;
235        } else if !v.is_empty() {
236            self.output += "\"";
237            self.output += v;
238            self.output += "\"";
239        }
240        Ok(())
241    }
242
243    fn serialize_bytes(self, v: &[u8]) -> Result<()> {
244        debug!("serialize bytes: {:?}", v);
245        self.serialize_str(&String::from_utf8(v.to_vec()).map_err(|_| Error::Syntax)?)
246    }
247
248    fn serialize_none(self) -> Result<()> {
249        debug!("serialize none");
250        self.serialize_unit()
251    }
252
253    fn serialize_some<T>(self, value: &T) -> Result<()>
254    where
255        T: ?Sized + serde::ser::Serialize,
256    {
257        debug!("serialize some");
258        value.serialize(self)
259    }
260
261    fn serialize_unit(self) -> Result<()> {
262        debug!("serialize unit");
263        Ok(())
264    }
265
266    fn serialize_unit_struct(self, _name: &'static str) -> Result<()> {
267        debug!("serialize unit struct: {}", _name);
268        self.serialize_unit()
269    }
270
271    fn serialize_unit_variant(
272        self,
273        _name: &'static str,
274        _variant_index: u32,
275        variant: &'static str,
276    ) -> Result<()> {
277        debug!("serialize unit variant: {}", variant);
278        self.serialize_str(variant)
279    }
280
281    fn serialize_newtype_struct<T>(self, _name: &'static str, value: &T) -> Result<()>
282    where
283        T: ?Sized + serde::ser::Serialize,
284    {
285        debug!("serialize newtype struct: {}", _name);
286        value.serialize(self)
287    }
288
289    fn serialize_newtype_variant<T>(
290        self,
291        _name: &'static str,
292        _variant_index: u32,
293        variant: &'static str,
294        value: &T,
295    ) -> Result<()>
296    where
297        T: ?Sized + serde::ser::Serialize,
298    {
299        debug!("serialize newtype struct variant: {}", variant);
300        if self.sequence {
301            return value.serialize(&mut *self);
302        }
303
304        self.key = true;
305        variant.serialize(&mut *self)?;
306        self.key = false;
307        self.output += "=";
308        value.serialize(&mut *self)?;
309        self.output += "\n";
310        Ok(())
311    }
312
313    fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq> {
314        debug!("serialize sequence");
315        if self.sequence {
316            return Err(Error::UnsupportedStructureInSeq);
317        }
318        self.sequence = true;
319        Ok(self)
320    }
321
322    fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple> {
323        debug!("serialize tuple");
324        self.serialize_seq(Some(len))
325    }
326
327    fn serialize_tuple_struct(
328        self,
329        _name: &'static str,
330        len: usize,
331    ) -> Result<Self::SerializeTupleStruct> {
332        debug!("serialize tuple struct");
333        self.serialize_seq(Some(len))
334    }
335
336    fn serialize_tuple_variant(
337        self,
338        _name: &'static str,
339        _variant_index: u32,
340        _variant: &'static str,
341        _len: usize,
342    ) -> Result<Self::SerializeTupleVariant> {
343        debug!("serialize tuple variant");
344        Ok(self)
345    }
346
347    fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap> {
348        debug!("serialize map");
349        if self.sequence {
350            return Err(Error::UnsupportedStructureInSeq);
351        }
352        Ok(self)
353    }
354
355    fn serialize_struct(self, _name: &'static str, len: usize) -> Result<Self::SerializeStruct> {
356        debug!("serialize struct: {}", _name);
357        self.serialize_map(Some(len))
358    }
359
360    fn serialize_struct_variant(
361        self,
362        _name: &'static str,
363        _variant_index: u32,
364        _variant: &'static str,
365        len: usize,
366    ) -> Result<Self::SerializeStructVariant> {
367        debug!("serialize struct variant: {}/{}", _name, _variant);
368        self.serialize_map(Some(len))
369    }
370}
371
372impl serde::ser::SerializeSeq for &mut Serializer {
373    type Ok = ();
374    type Error = Error;
375
376    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
377    where
378        T: ?Sized + serde::ser::Serialize,
379    {
380        debug!("serializing sequence element");
381        let r = value.serialize(&mut **self);
382        self.output += ",";
383        r
384    }
385
386    fn end(self) -> Result<()> {
387        debug!("ended serializing sequence element");
388        self.output.pop();
389        self.sequence = false;
390        self.strip_line_breaks();
391        Ok(())
392    }
393}
394
395impl serde::ser::SerializeTuple for &mut Serializer {
396    type Ok = ();
397    type Error = Error;
398
399    fn serialize_element<T>(&mut self, value: &T) -> Result<()>
400    where
401        T: ?Sized + serde::ser::Serialize,
402    {
403        debug!("serialize tuple element");
404        let r = value.serialize(&mut **self);
405        self.output += ",";
406        r
407    }
408
409    fn end(self) -> Result<()> {
410        debug!("ended serializing tuple element");
411        self.output.pop();
412        self.sequence = false;
413        self.strip_line_breaks();
414        Ok(())
415    }
416}
417
418impl serde::ser::SerializeTupleStruct for &mut Serializer {
419    type Ok = ();
420    type Error = Error;
421
422    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
423    where
424        T: ?Sized + serde::ser::Serialize,
425    {
426        debug!("serialize tuple struct field");
427        let r = value.serialize(&mut **self);
428        self.output += ",";
429        r
430    }
431
432    fn end(self) -> Result<()> {
433        debug!("ended serializing tuple struct field");
434        self.output.pop();
435        self.sequence = false;
436        Ok(())
437    }
438}
439
440impl serde::ser::SerializeTupleVariant for &mut Serializer {
441    type Ok = ();
442    type Error = Error;
443
444    fn serialize_field<T>(&mut self, value: &T) -> Result<()>
445    where
446        T: ?Sized + serde::ser::Serialize,
447    {
448        debug!("serialize tuple variant field");
449        let r = value.serialize(&mut **self);
450        self.output += ",";
451        r
452    }
453
454    fn end(self) -> Result<()> {
455        debug!("ended serializing tuple variant field");
456        self.output.pop();
457        self.sequence = false;
458        Ok(())
459    }
460}
461
462impl serde::ser::SerializeMap for &mut Serializer {
463    type Ok = ();
464    type Error = Error;
465
466    fn serialize_key<T>(&mut self, key: &T) -> Result<()>
467    where
468        T: ?Sized + serde::ser::Serialize,
469    {
470        debug!("serialize map key");
471        serialize_map_struct_key(self, key)
472    }
473
474    fn serialize_value<T>(&mut self, value: &T) -> Result<()>
475    where
476        T: ?Sized + serde::ser::Serialize,
477    {
478        debug!("serialize map value");
479        serialize_map_struct_value(self, value)
480    }
481
482    fn end(self) -> Result<()> {
483        debug!("ended serializing map");
484        self.strip_line_breaks();
485        Ok(())
486    }
487}
488
489impl serde::ser::SerializeStruct for &mut Serializer {
490    type Ok = ();
491    type Error = Error;
492
493    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
494    where
495        T: ?Sized + serde::ser::Serialize,
496    {
497        debug!("serializing struct field");
498
499        serialize_field(self, key, value)
500    }
501
502    fn end(self) -> Result<()> {
503        debug!("ended serializing struct field");
504        self.strip_line_breaks();
505        Ok(())
506    }
507}
508
509impl serde::ser::SerializeStructVariant for &mut Serializer {
510    type Ok = ();
511    type Error = Error;
512
513    fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<()>
514    where
515        T: ?Sized + serde::ser::Serialize,
516    {
517        debug!("serializing struct variant field");
518
519        serialize_field(self, key, value)
520    }
521
522    fn end(self) -> Result<()> {
523        debug!("ended serializing struct variant");
524        self.strip_line_breaks();
525        Ok(())
526    }
527}
528
529fn serialize_field<T>(ser: &'_ mut &'_ mut Serializer, key: &'static str, value: &T) -> Result<()>
530where
531    T: ?Sized + serde::ser::Serialize,
532{
533    serialize_map_struct_key(ser, key)?;
534    serialize_map_struct_value::<T>(ser, value)?;
535    Ok(())
536}
537
538fn serialize_map_struct_key<T>(ser: &'_ mut &'_ mut Serializer, key: &T) -> Result<()>
539where
540    T: ?Sized + serde::ser::Serialize,
541{
542    if ser.sequence {
543        return Err(Error::UnsupportedStructureInSeq);
544    }
545
546    ser.prefix_before = ser.prefix.clone();
547
548    let prefix = format!("{}{}", ser.prefix, '=');
549    if ser.output.ends_with(&prefix) {
550        ser.output = ser.output[..ser.output.len() - prefix.len()].into();
551    }
552
553    ser.key = true;
554    key.serialize(&mut **ser)?;
555    ser.key = false;
556    Ok(())
557}
558
559fn serialize_map_struct_value<T>(ser: &'_ mut &'_ mut Serializer, value: &T) -> Result<()>
560where
561    T: ?Sized + serde::ser::Serialize,
562{
563    if ser.sequence {
564        return Err(Error::UnsupportedStructureInSeq);
565    }
566
567    ser.output += "=";
568    value.serialize(&mut **ser)?;
569    ser.output += "\n";
570
571    ser.prefix = ser.prefix_before.clone();
572    Ok(())
573}
574
575#[cfg(test)]
576mod tests {
577    use std::{collections::HashMap, io::Cursor};
578
579    use super::{to_file, to_string, to_writer};
580    use crate::{Value, from_str};
581
582    #[test]
583    fn serialize_to_string_value() {
584        let env = Value::from_iter([("hello", "WORLD")]);
587
588        let output = to_string(&env).expect("Failed to serialize to string");
590
591        let expected = "HELLO=\"WORLD\"";
593        assert_eq!(expected, &output);
594
595        let deserialized = from_str::<Value>(&output).expect("Failed to deserialize to value");
597        assert_eq!(deserialized, env);
598    }
599
600    #[test]
601    fn serialize_to_string_struct() {
602        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
604        struct StructTestNested {
605            c: u8,
606        }
607
608        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
609        struct StructTest {
610            a: u8,
611            b: StructTestNested,
612        }
613
614        let env = StructTest {
615            a: 1,
616            b: StructTestNested { c: 2 },
617        };
618
619        let output = to_string(&env).expect("Failed to serialize to string");
621
622        assert_eq!("A=1\nB_C=2", output);
624    }
625
626    #[test]
627    fn serialize_to_string_sequence() {
628        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
631        struct SeqTest {
632            a: Vec<String>,
633            b: String,
634        }
635
636        let env = SeqTest {
637            a: vec!["HELLO".into(), "WORLD".into()],
638            b: "control value".into(),
639        };
640
641        let output = to_string(&env).expect("Failed to serialize to string");
643
644        let expected = "A=\"HELLO\",\"WORLD\"\nB=\"control value\"";
646        assert_eq!(expected, &output);
647
648        let deserialized = from_str::<SeqTest>(&output).expect("Failed to deserialize to struct");
650        assert_eq!(deserialized, env);
651    }
652
653    #[test]
654    fn serialize_to_string_enum() {
655        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
657        enum EnumTestEnum {
658            HELLO,
659            WORLD,
660        }
661
662        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
663        struct EnumTest {
664            a: EnumTestEnum,
665        }
666
667        let env = EnumTest {
668            a: EnumTestEnum::HELLO,
669        };
670
671        let output = to_string(&env).expect("Failed to serialize to string");
673
674        let expected = "A=\"HELLO\"";
676        assert_eq!(expected, &output);
677
678        let deserialized = from_str::<EnumTest>(&output).expect("Failed to deserialize to struct");
680        assert_eq!(deserialized, env);
681    }
682
683    #[test]
684    fn serialize_to_string_numbers() {
685        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
687        struct NumberTest {
688            u8: u8,
689            u16: u16,
690            u32: u32,
691            u64: u64,
692            i8: i8,
693            i16: i16,
694            i32: i32,
695            i64: i64,
696            f32: f32,
697            f64: f64,
698            usize: usize,
699        }
700
701        let env = NumberTest {
702            u8: 255,
703            u16: 65535,
704            u32: 4294967295,
705            u64: 18446744073709551615,
706            i8: -128,
707            i16: -32768,
708            i32: -2147483648,
709            i64: -9223372036854775808,
710            f32: -3.5,
711            f64: 3.5,
712            usize: 18446744073709551615,
713        };
714
715        let output = to_string(&env).expect("Failed to serialize to string");
717
718        let expected = "U8=255\nU16=65535\nU32=4294967295\nU64=18446744073709551615\nI8=-128\nI16=-32768\nI32=-2147483648\nI64=-9223372036854775808\nF32=-3.5\nF64=3.5\nUSIZE=18446744073709551615";
720        assert_eq!(expected, &output);
721
722        let deserialized = from_str::<NumberTest>(&output).expect("Failed to deserialize to struct");
724        assert_eq!(deserialized, env);
725    }
726
727    #[test]
728    fn serialize_to_string_bool() {
729        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
731        struct BoolTest {
732            a: bool,
733            b: bool,
734        }
735
736        let env = BoolTest { a: true, b: false };
737
738        let output = to_string(&env).expect("Failed to serialize to string");
740
741        let expected = "A=true\nB=false";
743        assert_eq!(expected, &output);
744
745        let deserialized = from_str::<BoolTest>(&output).expect("Failed to deserialize to struct");
747        assert_eq!(deserialized, env);
748    }
749
750    #[test]
751    fn serialize_to_string_option() {
752        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
754        struct OptionTest {
755            a: Option<String>,
756            b: Option<String>,
757        }
758
759        let env = OptionTest {
760            a: Some("HELLO".into()),
761            b: None,
762        };
763
764        let output = to_string(&env).expect("Failed to serialize to string");
766
767        let expected = "A=\"HELLO\"\nB=";
769        assert_eq!(expected, &output);
770
771        let deserialized = from_str::<OptionTest>(&output).expect("Failed to deserialize to struct");
774        assert_eq!(deserialized.a, env.a);
775    }
776
777    #[test]
778    fn serialize_to_string_hashmap() {
779        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
781        struct MapTest {
782            #[serde(flatten)]
783            inner: HashMap<String, String>,
784        }
785
786        let mut env = MapTest {
787            inner: HashMap::new(),
788        };
789        env.inner.insert("hello".into(), "WORLD".into());
790
791        let output = to_string(&env).expect("Failed to serialize to string");
793
794        let expected = "HELLO=\"WORLD\"";
796        assert_eq!(expected, &output);
797
798        let deserialized = from_str::<MapTest>(&output).expect("Failed to deserialize to struct");
800        assert_eq!(deserialized, env);
801    }
802
803    #[test]
804    fn serialize_to_string_nested_hashmap() {
805        #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
807        struct NestedMapTest {
808            inner: HashMap<String, String>,
809        }
810
811        let env = NestedMapTest {
812            inner: HashMap::from([("HELLO".into(), "WORLD".into())]),
813        };
814
815        let output = to_string(&env).expect("Failed to serialize to string");
817
818        let expected = "INNER_HELLO=\"WORLD\"";
820        assert_eq!(expected, &output);
821    }
822
823    #[test]
824    fn serialize_to_writer() {
825        let env = Value::from_iter([("HELLO", "WORLD")]);
827
828        let mut writer = Cursor::new(Vec::new());
829
830        to_writer(&mut writer, &env).expect("Failed to serialize to writer");
832
833        let expected_output = "HELLO=\"WORLD\"";
835        let output = String::from_utf8(writer.into_inner()).expect("Invalid UTF-8 sequence");
836        assert_eq!(expected_output, output);
837    }
838
839    #[test]
840    fn serialize_to_file() {
841        let env = Value::from_iter([("HELLO", "WORLD")]);
843
844        let file = tempfile::NamedTempFile::new_in(std::env::temp_dir()).expect("Failed to create temp file");
846
847        to_file(&file.path(), &env).expect("Failed to serialize to file");
849
850        let expected_output = "HELLO=\"WORLD\"";
852        let output = std::fs::read_to_string(file.path()).expect("Failed to read file");
853        assert_eq!(expected_output, output);
854    }
855}