format_ende/
lib.rs

1//! This crate provides the `FormatInfo`, `FormatEncoder`, and `FormatDecoder` traits.
2//! These traits allow to encode/decode data from/to a generic format.
3//!
4//! # Example
5//! ```
6//! use format_ende::FormatInfo;
7//! use format_ende::FormatEncoder;
8//!
9//! /// Print given value encoded with the given encoder
10//! fn print<E, V>(encoder: &mut E, value: &V) where
11//!     E: FormatInfo,
12//!     E: FormatEncoder<V>,
13//!     E::EncodeError: std::fmt::Debug,
14//! {
15//!     println!(
16//!         "{} as {}:",
17//!         std::any::type_name::<V>(),
18//!         encoder.file_extension()
19//!     );
20//!     let mut stdout = std::io::stdout();
21//!     encoder.encode(&mut stdout, value).unwrap();
22//!     println!();
23//! }
24//! ```
25
26use std::error::Error;
27use std::io;
28
29/// Information about a specific format, such as its file extension
30pub trait FormatInfo {
31    /// Returns the file extension associated with this format (without the dot)
32    fn file_extension(&self) -> &str;
33
34    /// Returns whether the format is UTF-8 based (e.g. JSON, YAML)
35    fn is_utf8(&self) -> bool {
36        false
37    }
38}
39
40/// A trait for encoding values of type `V` into a specific format
41pub trait FormatEncoder<V: ?Sized> {
42    /// The error type that can occur during encoding
43    type EncodeError;
44
45    /// Encodes the given value into the provided writer
46    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError>;
47}
48
49/// A trait for decoding values of type `V` from a specific format
50pub trait FormatDecoder<V> {
51    /// The error type that can occur during decoding
52    type DecodeError;
53
54    /// Decodes a value from the provided reader
55    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError>;
56}
57
58/// A trait object version of `FormatEncoder` for dynamic dispatch
59pub trait FormatEncoderDyn<V: ?Sized, E = Box<dyn Error>> {
60    /// Encodes the given value into the provided writer
61    fn encode_dyn(&mut self, writer: &mut dyn io::Write, value: &V) -> Result<(), E>;
62}
63
64/// A trait object version of `FormatDecoder` for dynamic dispatch
65pub trait FormatDecoderDyn<V, E = Box<dyn Error>> {
66    /// Decodes a value from the provided reader
67    fn decode_dyn(&mut self, reader: &mut dyn io::Read) -> Result<V, E>;
68}
69
70impl<T, V> FormatEncoder<V> for &mut T
71where
72    T: ?Sized,
73    V: ?Sized,
74    T: FormatEncoder<V>,
75{
76    type EncodeError = T::EncodeError;
77
78    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError> {
79        T::encode(self, writer, value)
80    }
81}
82
83impl<T, V> FormatEncoder<V> for Box<T>
84where
85    T: ?Sized,
86    V: ?Sized,
87    T: FormatEncoder<V>,
88{
89    type EncodeError = T::EncodeError;
90
91    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError> {
92        T::encode(self, writer, value)
93    }
94}
95
96impl<T, V> FormatDecoder<V> for &mut T
97where
98    T: ?Sized,
99    T: FormatDecoder<V>,
100{
101    type DecodeError = T::DecodeError;
102
103    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError> {
104        T::decode(self, reader)
105    }
106}
107
108impl<T, V> FormatDecoder<V> for Box<T>
109where
110    T: ?Sized,
111    T: FormatDecoder<V>,
112{
113    type DecodeError = T::DecodeError;
114
115    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError> {
116        T::decode(self, reader)
117    }
118}
119
120impl<T, V, E> FormatEncoderDyn<V, E> for T
121where
122    T: FormatEncoder<V> + ?Sized,
123    V: ?Sized,
124    T::EncodeError: Into<E>,
125{
126    fn encode_dyn(&mut self, writer: &mut dyn io::Write, value: &V) -> Result<(), E> {
127        self.encode(writer, value).map_err(Into::into)
128    }
129}
130
131impl<T, V, E> FormatDecoderDyn<V, E> for T
132where
133    T: FormatDecoder<V> + ?Sized,
134    T::DecodeError: Into<E>,
135{
136    fn decode_dyn(&mut self, reader: &mut dyn io::Read) -> Result<V, E> {
137        self.decode(reader).map_err(Into::into)
138    }
139}