1 //! Serializing Rust structures into TOML.
2 //!
3 //! This module contains all the Serde support for serializing Rust structures into TOML.
4 
5 mod array;
6 mod key;
7 mod map;
8 mod pretty;
9 mod value;
10 
11 pub(crate) use array::*;
12 pub(crate) use key::*;
13 pub(crate) use map::*;
14 
15 use crate::visit_mut::VisitMut;
16 
17 /// Errors that can occur when deserializing a type.
18 #[derive(Debug, Clone, PartialEq, Eq)]
19 #[non_exhaustive]
20 pub enum Error {
21     /// Type could not be serialized to TOML
22     UnsupportedType(Option<&'static str>),
23     /// Value was out of range for the given type
24     OutOfRange(Option<&'static str>),
25     /// `None` could not be serialized to TOML
26     UnsupportedNone,
27     /// Key was not convertible to `String` for serializing to TOML
28     KeyNotString,
29     /// A serialized date was invalid
30     DateInvalid,
31     /// Other serialization error
32     Custom(String),
33 }
34 
35 impl Error {
custom<T>(msg: T) -> Self where T: std::fmt::Display,36     pub(crate) fn custom<T>(msg: T) -> Self
37     where
38         T: std::fmt::Display,
39     {
40         Error::Custom(msg.to_string())
41     }
42 }
43 
44 impl serde::ser::Error for Error {
custom<T>(msg: T) -> Self where T: std::fmt::Display,45     fn custom<T>(msg: T) -> Self
46     where
47         T: std::fmt::Display,
48     {
49         Self::custom(msg)
50     }
51 }
52 
53 impl std::fmt::Display for Error {
fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result54     fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
55         match self {
56             Self::UnsupportedType(Some(t)) => write!(formatter, "unsupported {t} type"),
57             Self::UnsupportedType(None) => write!(formatter, "unsupported rust type"),
58             Self::OutOfRange(Some(t)) => write!(formatter, "out-of-range value for {t} type"),
59             Self::OutOfRange(None) => write!(formatter, "out-of-range value"),
60             Self::UnsupportedNone => "unsupported None value".fmt(formatter),
61             Self::KeyNotString => "map key was not a string".fmt(formatter),
62             Self::DateInvalid => "a serialized date was invalid".fmt(formatter),
63             Self::Custom(s) => s.fmt(formatter),
64         }
65     }
66 }
67 
68 impl From<crate::TomlError> for Error {
from(e: crate::TomlError) -> Error69     fn from(e: crate::TomlError) -> Error {
70         Self::custom(e)
71     }
72 }
73 
74 impl From<Error> for crate::TomlError {
from(e: Error) -> crate::TomlError75     fn from(e: Error) -> crate::TomlError {
76         Self::custom(e.to_string(), None)
77     }
78 }
79 
80 impl std::error::Error for Error {}
81 
82 /// Serialize the given data structure as a TOML byte vector.
83 ///
84 /// Serialization can fail if `T`'s implementation of `Serialize` decides to
85 /// fail, if `T` contains a map with non-string keys, or if `T` attempts to
86 /// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
87 #[cfg(feature = "display")]
to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error> where T: serde::ser::Serialize,88 pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error>
89 where
90     T: serde::ser::Serialize,
91 {
92     to_string(value).map(|e| e.into_bytes())
93 }
94 
95 /// Serialize the given data structure as a String of TOML.
96 ///
97 /// Serialization can fail if `T`'s implementation of `Serialize` decides to
98 /// fail, if `T` contains a map with non-string keys, or if `T` attempts to
99 /// serialize an unsupported datatype such as an enum, tuple, or tuple struct.
100 ///
101 /// # Examples
102 ///
103 /// ```
104 /// use serde::Serialize;
105 ///
106 /// #[derive(Serialize)]
107 /// struct Config {
108 ///     database: Database,
109 /// }
110 ///
111 /// #[derive(Serialize)]
112 /// struct Database {
113 ///     ip: String,
114 ///     port: Vec<u16>,
115 ///     connection_max: u32,
116 ///     enabled: bool,
117 /// }
118 ///
119 /// let config = Config {
120 ///     database: Database {
121 ///         ip: "192.168.1.1".to_string(),
122 ///         port: vec![8001, 8002, 8003],
123 ///         connection_max: 5000,
124 ///         enabled: false,
125 ///     },
126 /// };
127 ///
128 /// let toml = toml_edit::ser::to_string(&config).unwrap();
129 /// println!("{}", toml)
130 /// ```
131 #[cfg(feature = "display")]
to_string<T: ?Sized>(value: &T) -> Result<String, Error> where T: serde::ser::Serialize,132 pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error>
133 where
134     T: serde::ser::Serialize,
135 {
136     to_document(value).map(|e| e.to_string())
137 }
138 
139 /// Serialize the given data structure as a "pretty" String of TOML.
140 ///
141 /// This is identical to `to_string` except the output string has a more
142 /// "pretty" output. See `ValueSerializer::pretty` for more details.
143 #[cfg(feature = "display")]
to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error> where T: serde::ser::Serialize,144 pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error>
145 where
146     T: serde::ser::Serialize,
147 {
148     let mut document = to_document(value)?;
149     pretty::Pretty.visit_document_mut(&mut document);
150     Ok(document.to_string())
151 }
152 
153 /// Serialize the given data structure into a TOML document.
154 ///
155 /// This would allow custom formatting to be applied, mixing with format preserving edits, etc.
to_document<T: ?Sized>(value: &T) -> Result<crate::Document, Error> where T: serde::ser::Serialize,156 pub fn to_document<T: ?Sized>(value: &T) -> Result<crate::Document, Error>
157 where
158     T: serde::ser::Serialize,
159 {
160     let value = value.serialize(ValueSerializer::new())?;
161     let item = crate::Item::Value(value);
162     let root = item
163         .into_table()
164         .map_err(|_| Error::UnsupportedType(None))?;
165     Ok(root.into())
166 }
167 
168 pub use value::ValueSerializer;
169