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