Skip to main content

singlefile/
format.rs

1//! How to interpret the contents of files.
2
3pub mod default_formats;
4
5pub use self::default_formats::PlainBytes;
6pub use self::default_formats::PlainUtf8;
7
8use std::io::{Cursor, BufReader, BufWriter, Read, Write};
9
10/// A trait that describes how a file's contents should be interpreted.
11///
12/// Usually, you will want to implement a simple wrapper over your file format's
13/// `to_writer` and `from_reader` functions, using your favorite serialization framework.
14///
15/// # Example
16/// ```no_run
17/// # use serde::ser::Serialize;
18/// # use serde::de::DeserializeOwned;
19/// # use singlefile::FileFormat;
20/// # use singlefile_formats::data::json_serde::original as serde_json;
21/// # use std::io::{Read, Write};
22/// struct Json;
23///
24/// impl<T> FileFormat<T> for Json
25/// where T: Serialize + DeserializeOwned {
26///   type FormatError = serde_json::Error;
27///
28///   fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
29///     serde_json::to_writer_pretty(writer, value).map_err(From::from)
30///   }
31///
32///   fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
33///     serde_json::from_reader(reader).map_err(From::from)
34///   }
35/// }
36/// ```
37#[allow(clippy::wrong_self_convention)]
38pub trait FileFormat<T> {
39  /// The type of error to return from `to_writer` and `from_reader`.
40  type FormatError: std::error::Error;
41
42  /// Deserialize a value from a `Read` stream.
43  ///
44  /// If you are reading directly from a [`File`][std::fs::File], you should consider
45  /// using [`from_reader_buffered`][FileFormat::from_reader_buffered] instead.
46  fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError>;
47
48  /// Identical to [`FileFormat::from_reader`], however the provided reader is buffered with [`BufReader`].
49  ///
50  /// You should override this function if your file format reads
51  /// to a buffer internally in order to avoid double-buffering.
52  #[inline]
53  fn from_reader_buffered<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
54    self.from_reader(BufReader::new(reader))
55  }
56
57  /// Deserialize a value from a byte vec.
58  #[inline]
59  fn from_buffer(&self, buf: &[u8]) -> Result<T, Self::FormatError> {
60    self.from_reader(buf)
61  }
62
63  /// Serialize a value into a `Write` stream.
64  ///
65  /// If you are writing directly to a [`File`][std::fs::File], you should consider
66  /// using [`to_writer_buffered`][FileFormat::to_writer_buffered] instead.
67  fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError>;
68
69  /// Identical to [`FileFormat::to_writer`], however the provided writer is buffered with [`BufWriter`].
70  ///
71  /// You should override this function if your file format writes
72  /// to a buffer internally in order to avoid double-buffering.
73  #[inline]
74  fn to_writer_buffered<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
75    self.to_writer(BufWriter::new(writer), value)
76  }
77
78  /// Serialize a value into a byte vec.
79  fn to_buffer(&self, value: &T) -> Result<Vec<u8>, Self::FormatError> {
80    let mut buf = Cursor::new(Vec::new());
81    self.to_writer(&mut buf, value)?;
82    Ok(buf.into_inner())
83  }
84}
85
86/// A trait that indicates a file's contents will always be valid UTF-8.
87#[allow(clippy::wrong_self_convention)]
88pub trait FileFormatUtf8<T>: FileFormat<T> {
89  /// Deserialize a buffer from a string slice.
90  fn from_string_buffer(&self, buf: &str) -> Result<T, Self::FormatError>;
91
92  /// Serialize a value into a string buffer.
93  fn to_string_buffer(&self, value: &T) -> Result<String, Self::FormatError>;
94}
95
96macro_rules! impl_file_format_delegate {
97  (<$Format:ident> $Type:ty) => (
98    impl<T, $Format: FileFormat<T>> FileFormat<T> for $Type {
99      type FormatError = <$Format as FileFormat<T>>::FormatError;
100
101      #[inline]
102      fn from_reader_buffered<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
103        $Format::from_reader_buffered(self, reader)
104      }
105
106      #[inline]
107      fn from_reader<R: Read>(&self, reader: R) -> Result<T, Self::FormatError> {
108        $Format::from_reader(self, reader)
109      }
110
111      #[inline]
112      fn from_buffer(&self, buf: &[u8]) -> Result<T, Self::FormatError> {
113        $Format::from_buffer(self, buf)
114      }
115
116      #[inline]
117      fn to_writer<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
118        $Format::to_writer(self, writer, value)
119      }
120
121      #[inline]
122      fn to_writer_buffered<W: Write>(&self, writer: W, value: &T) -> Result<(), Self::FormatError> {
123        $Format::to_writer_buffered(self, writer, value)
124      }
125
126      #[inline]
127      fn to_buffer(&self, value: &T) -> Result<Vec<u8>, Self::FormatError> {
128        $Format::to_buffer(self, value)
129      }
130    }
131
132    impl<T, $Format: FileFormatUtf8<T>> FileFormatUtf8<T> for $Type {
133      fn from_string_buffer(&self, buf: &str) -> Result<T, Self::FormatError> {
134        $Format::from_string_buffer(self, buf)
135      }
136
137      fn to_string_buffer(&self, value: &T) -> Result<String, Self::FormatError> {
138        $Format::to_string_buffer(self, value)
139      }
140    }
141  );
142}
143
144impl_file_format_delegate!(<Format> &Format);
145impl_file_format_delegate!(<Format> std::boxed::Box<Format>);
146impl_file_format_delegate!(<Format> std::rc::Rc<Format>);
147impl_file_format_delegate!(<Format> std::sync::Arc<Format>);