singlefile_formats/data/
toml_serde.rs

1#![cfg_attr(docsrs, doc(cfg(feature = "toml-serde")))]
2#![cfg(feature = "toml-serde")]
3
4//! Defines a [`FileFormat`] using the TOML data format.
5
6pub extern crate toml as original;
7
8use serde::ser::Serialize;
9use serde::de::DeserializeOwned;
10use singlefile::{FileFormat, FileFormatUtf8};
11use thiserror::Error;
12
13use std::io::{Read, Write};
14
15/// An error that can occur while using [`Toml`].
16#[derive(Debug, Error)]
17pub enum TomlError {
18  /// An error occured while reading data to the string buffer.
19  #[error(transparent)]
20  IoError(#[from] std::io::Error),
21  /// An error occurred while serializing.
22  #[error(transparent)]
23  SerializeError(#[from] toml::ser::Error),
24  /// An error occurred while deserializing.
25  #[error(transparent)]
26  DeserializeError(#[from] toml::de::Error)
27}
28
29/// A [`FileFormat`] corresponding to the TOML data format.
30/// Implemented using the [`toml`] crate, only compatible with [`serde`] types.
31///
32/// This type provides an optional constant generic parameter for configuring pretty-print.
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
34pub struct Toml<const PRETTY: bool = true>;
35
36/// Since the [`toml`] crate exposes no writer-based operations, all operations within this implementation are buffered.
37impl<T, const PRETTY: bool> FileFormat<T> for Toml<PRETTY>
38where T: Serialize + DeserializeOwned {
39  type FormatError = TomlError;
40
41  fn from_reader<R: Read>(&self, mut reader: R) -> Result<T, Self::FormatError> {
42    let mut buf = String::new();
43    reader.read_to_string(&mut buf)?;
44    toml::de::from_str(&buf).map_err(From::from)
45  }
46
47  #[inline]
48  fn from_reader_buffered<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
49    // no need to pass `reader` in with a `BufReader` as that would cause things to be buffered twice
50    self.from_reader(reader)
51  }
52
53  fn to_writer<W: Write>(&self, mut writer: W, value: &T) -> Result<(), Self::FormatError> {
54    let buf = self.to_buffer(value)?;
55    writer.write_all(&buf).map_err(From::from)
56  }
57
58  #[inline]
59  fn to_writer_buffered<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
60    // no need to pass `writer` in with a `BufWriter` as that would cause things to be buffered twice
61    self.to_writer(writer, value)
62  }
63
64  #[inline]
65  fn to_buffer(&self, value: &T) -> Result<Vec<u8>, Self::FormatError> {
66    self.to_string_buffer(value).map(String::into_bytes)
67  }
68}
69
70impl<T, const PRETTY: bool> FileFormatUtf8<T> for Toml<PRETTY>
71where T: Serialize + DeserializeOwned {
72  fn from_string_buffer(&self, buf: &str) -> Result<T, Self::FormatError> {
73    Ok(toml::de::from_str(buf)?)
74  }
75
76  fn to_string_buffer(&self, value: &T) -> Result<String, Self::FormatError> {
77    Ok(match PRETTY {
78      true => toml::ser::to_string_pretty(value),
79      false => toml::ser::to_string(value)
80    }?)
81  }
82}
83
84/// A shortcut type to a [`Toml`] with pretty-print enabled.
85pub type PrettyToml = Toml<true>;
86/// A shortcut type to a [`Toml`] with pretty-print disabled.
87pub type RegularToml = Toml<false>;
88
89/// A shortcut type to a [`Compressed`][crate::compression::Compressed] [`Toml`].
90/// Provides parameters for compression format and pretty-print configuration (defaulting to off).
91#[cfg_attr(docsrs, doc(cfg(feature = "compression")))]
92#[cfg(feature = "compression")]
93pub type CompressedToml<C, const PRETTY: bool = false> = crate::compression::Compressed<C, Toml<PRETTY>>;