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