unfolder 0.0.3

library and executable to unfold a file into a folder and fold a previously unfolded folder into a file
Documentation
use std::fmt::Display;

use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum Error {
    IOError(String),
    FlattenFileInputError(String),
    FlattenFileOutputError(String),
    UnflattenFileInputError(String),
    UnflattenFileOutputError(String),
    InvalidIndexError(String),
    MissingIndexError(String),
    UnreadableIndexError(String),
    CorruptedDataError(String),
    ChecksumMismatch(String),
}
impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        write!(
            f,
            "{}: {}",
            self.variant(),
            match self {
                Self::IOError(e) => e.to_string(),
                Self::FlattenFileInputError(e) => e.to_string(),
                Self::FlattenFileOutputError(e) => e.to_string(),
                Self::UnflattenFileInputError(e) => e.to_string(),
                Self::UnflattenFileOutputError(e) => e.to_string(),
                Self::InvalidIndexError(e) => e.to_string(),
                Self::MissingIndexError(e) => e.to_string(),
                Self::UnreadableIndexError(e) => e.to_string(),
                Self::CorruptedDataError(e) => e.to_string(),
                Self::ChecksumMismatch(e) => e.to_string(),
            }
        )
    }
}

impl Error {
    pub fn variant(&self) -> String {
        match self {
            Error::IOError(_) => "IOError",
            Self::FlattenFileInputError(_) => "FlattenFileInputError",
            Self::FlattenFileOutputError(_) => "FlattenFileOutputError",
            Self::UnflattenFileInputError(_) => "UnflattenFileInputError",
            Self::UnflattenFileOutputError(_) => "UnflattenFileOutputError",
            Self::InvalidIndexError(_) => "InvalidIndexError",
            Self::MissingIndexError(_) => "MissingIndexError",
            Self::UnreadableIndexError(_) => "UnreadableIndexError",
            Self::CorruptedDataError(_) => "CorruptedDataError",
            Self::ChecksumMismatch(_) => "ChecksumMismatch",
       }
        .to_string()
    }
}

impl std::error::Error for Error {}
impl From<std::io::Error> for Error {
    fn from(e: std::io::Error) -> Self {
        Error::IOError(format!("{}", e))
    }
}
impl From<iocore::Error> for Error {
    fn from(e: iocore::Error) -> Self {
        Error::IOError(format!("{}", e))
    }
}
pub type Result<T> = std::result::Result<T, Error>;

#[derive(Debug, Clone)]
pub enum Exit {
    Success,
    Error(Error),
}
impl std::process::Termination for Exit {
    fn report(self) -> std::process::ExitCode {
        match &self {
            Exit::Success => std::process::ExitCode::from(0),
            Exit::Error(error) => {
                eprintln!("{}", error);
                std::process::ExitCode::from(1)
            },
        }
    }
}
impl<T> From<std::result::Result<T, Error>> for Exit {
    fn from(result: std::result::Result<T, Error>) -> Exit {
        match result {
            Ok(_) => Exit::Success,
            Err(e) => Exit::Error(e),
        }
    }
}