format-ende 0.1.1

Set of traits allowing to encode/decode data from/to a generic format
Documentation
//! This crate provides the `FormatInfo`, `FormatEncoder`, and `FormatDecoder` traits.
//! These traits allow to encode/decode data from/to a generic format.
//!
//! # Example
//! ```
//! use format_ende::FormatInfo;
//! use format_ende::FormatEncoder;
//!
//! /// Print given value encoded with the given encoder
//! fn print<E, V>(encoder: &mut E, value: &V) where
//!     E: FormatInfo,
//!     E: FormatEncoder<V>,
//!     E::EncodeError: std::fmt::Debug,
//! {
//!     println!(
//!         "{} as {}:",
//!         std::any::type_name::<V>(),
//!         encoder.file_extension()
//!     );
//!     let mut stdout = std::io::stdout();
//!     encoder.encode(&mut stdout, value).unwrap();
//!     println!();
//! }
//! ```

use std::error::Error;
use std::io;

/// Information about a specific format, such as its file extension
pub trait FormatInfo {
    /// Returns the file extension associated with this format (without the dot)
    fn file_extension(&self) -> &str;

    /// Returns whether the format is UTF-8 based (e.g. JSON, YAML)
    fn is_utf8(&self) -> bool {
        false
    }
}

/// A trait for encoding values of type `V` into a specific format
pub trait FormatEncoder<V: ?Sized> {
    /// The error type that can occur during encoding
    type EncodeError;

    /// Encodes the given value into the provided writer
    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError>;
}

/// A trait for decoding values of type `V` from a specific format
pub trait FormatDecoder<V> {
    /// The error type that can occur during decoding
    type DecodeError;

    /// Decodes a value from the provided reader
    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError>;
}

/// A trait object version of `FormatEncoder` for dynamic dispatch
pub trait FormatEncoderDyn<V: ?Sized, E = Box<dyn Error>> {
    /// Encodes the given value into the provided writer
    fn encode_dyn(&mut self, writer: &mut dyn io::Write, value: &V) -> Result<(), E>;
}

/// A trait object version of `FormatDecoder` for dynamic dispatch
pub trait FormatDecoderDyn<V, E = Box<dyn Error>> {
    /// Decodes a value from the provided reader
    fn decode_dyn(&mut self, reader: &mut dyn io::Read) -> Result<V, E>;
}

impl<T, V> FormatEncoder<V> for &mut T
where
    T: ?Sized,
    V: ?Sized,
    T: FormatEncoder<V>,
{
    type EncodeError = T::EncodeError;

    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError> {
        T::encode(self, writer, value)
    }
}

impl<T, V> FormatEncoder<V> for Box<T>
where
    T: ?Sized,
    V: ?Sized,
    T: FormatEncoder<V>,
{
    type EncodeError = T::EncodeError;

    fn encode(&mut self, writer: impl io::Write, value: &V) -> Result<(), Self::EncodeError> {
        T::encode(self, writer, value)
    }
}

impl<T, V> FormatDecoder<V> for &mut T
where
    T: ?Sized,
    T: FormatDecoder<V>,
{
    type DecodeError = T::DecodeError;

    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError> {
        T::decode(self, reader)
    }
}

impl<T, V> FormatDecoder<V> for Box<T>
where
    T: ?Sized,
    T: FormatDecoder<V>,
{
    type DecodeError = T::DecodeError;

    fn decode(&mut self, reader: impl io::Read) -> Result<V, Self::DecodeError> {
        T::decode(self, reader)
    }
}

impl<T, V, E> FormatEncoderDyn<V, E> for T
where
    T: FormatEncoder<V> + ?Sized,
    V: ?Sized,
    T::EncodeError: Into<E>,
{
    fn encode_dyn(&mut self, writer: &mut dyn io::Write, value: &V) -> Result<(), E> {
        self.encode(writer, value).map_err(Into::into)
    }
}

impl<T, V, E> FormatDecoderDyn<V, E> for T
where
    T: FormatDecoder<V> + ?Sized,
    T::DecodeError: Into<E>,
{
    fn decode_dyn(&mut self, reader: &mut dyn io::Read) -> Result<V, E> {
        self.decode(reader).map_err(Into::into)
    }
}