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
11pub(crate) use array::*;
12pub(crate) use key::*;
13pub(crate) use map::*;
14
15use crate::visit_mut::VisitMut;
16
17/// Errors that can occur when deserializing a type.
18#[derive(Debug, Clone, PartialEq, Eq)]
19#[non_exhaustive]
20pub 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
35impl Error {
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
44impl serde::ser::Error for Error {
45    fn custom<T>(msg: T) -> Self
46    where
47        T: std::fmt::Display,
48    {
49        Self::custom(msg)
50    }
51}
52
53impl std::fmt::Display for Error {
54    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
68impl From<crate::TomlError> for Error {
69    fn from(e: crate::TomlError) -> Error {
70        Self::custom(e)
71    }
72}
73
74impl From<Error> for crate::TomlError {
75    fn from(e: Error) -> crate::TomlError {
76        Self::custom(e.to_string(), None)
77    }
78}
79
80impl 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")]
88pub fn to_vec<T>(value: &T) -> Result<Vec<u8>, Error>
89where
90    T: serde::ser::Serialize + ?Sized,
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")]
132pub fn to_string<T>(value: &T) -> Result<String, Error>
133where
134    T: serde::ser::Serialize + ?Sized,
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")]
144pub fn to_string_pretty<T>(value: &T) -> Result<String, Error>
145where
146    T: serde::ser::Serialize + ?Sized,
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.
156pub fn to_document<T>(value: &T) -> Result<crate::DocumentMut, Error>
157where
158    T: serde::ser::Serialize + ?Sized,
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
168pub use value::ValueSerializer;