toml_edit/ser/
mod.rs

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