use std::io::{Read, Write};
#[derive(Debug)]
pub enum EncodeError {
    Io(std::io::Error),
}
impl std::fmt::Display for EncodeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "EncodeError({})",
            match self {
                Self::Io(e) => e.to_string(),
            }
        )
    }
}
impl From<std::io::Error> for EncodeError {
    fn from(value: std::io::Error) -> Self {
        Self::Io(value)
    }
}
#[derive(Debug)]
pub enum DecodeError {
    Io(std::io::Error),
    Utf8(std::str::Utf8Error),
    InvalidVersion,
    InvalidTag((&'static str, u8)),
    InvalidTrailer,
    InvalidHeader(&'static str),
}
impl std::fmt::Display for DecodeError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "DecodeError({})",
            match self {
                Self::Io(e) => e.to_string(),
                e => format!("{e:?}"),
            }
        )
    }
}
impl From<std::io::Error> for DecodeError {
    fn from(value: std::io::Error) -> Self {
        Self::Io(value)
    }
}
impl From<std::str::Utf8Error> for DecodeError {
    fn from(value: std::str::Utf8Error) -> Self {
        Self::Utf8(value)
    }
}
pub trait Encode {
    fn encode_into<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError>;
    fn encode_into_vec(&self) -> Result<Vec<u8>, EncodeError> {
        let mut v = vec![];
        self.encode_into(&mut v)?;
        Ok(v)
    }
}
pub trait Decode {
    fn decode_from<R: Read>(reader: &mut R) -> Result<Self, DecodeError>
    where
        Self: Sized;
}