libvctrl_handler 5.2.0

Fundamental contracts for building a version control system – no implementations, only traits and types
Documentation
use alloc::sync::Arc;
use core::error::Error;
use core::fmt;
use std::io;

use crate::constants::HASH_LENGTH;
use crate::types::Hash;

#[non_exhaustive]
#[derive(Clone, Debug)]
pub enum VctrlError {
    CorruptedData(String),
    DuplicateParent,
    ExceededMaxSize(String),
    InvalidBlameRange,
    InvalidEmail(String),
    InvalidHashLength(usize),
    InvalidName(String),
    InvalidTimezoneOffset(i16),
    InvalidTreeStructure(String),
    IoError(Arc<io::Error>),
    ObjectNotFound(Hash),
    Other(String),
    RefNotFound(String),
    SerializationError(String),
}

impl fmt::Display for VctrlError {
    #[inline]
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::CorruptedData(msg) => write!(f, "Corrupted data: {msg}"),
            Self::DuplicateParent => write!(f, "Duplicate parent in commit"),
            Self::ExceededMaxSize(msg) => write!(f, "Exceeded max size: {msg}"),
            Self::InvalidBlameRange => write!(f, "Invalid blame range"),
            Self::InvalidEmail(msg) => write!(f, "Invalid email: '{msg}'"),
            Self::InvalidHashLength(len) => {
                write!(
                    f,
                    "Invalid hash length: expected {HASH_LENGTH} bytes, got {len}"
                )
            }
            Self::InvalidName(name) => write!(f, "Invalid name: '{name}'"),
            Self::InvalidTimezoneOffset(offset) => {
                write!(f, "Invalid timezone offset: {offset}")
            }
            Self::InvalidTreeStructure(msg) => write!(f, "Invalid tree structure: {msg}"),
            Self::IoError(err) => write!(f, "I/O error: {}", err.as_ref()),
            Self::ObjectNotFound(hash) => write!(f, "Object not found: {hash}"),
            Self::Other(msg) => write!(f, "{msg}"),
            Self::RefNotFound(name) => write!(f, "Reference not found: '{name}'"),
            Self::SerializationError(msg) => write!(f, "Serialization error: {msg}"),
        }
    }
}

impl Error for VctrlError {
    #[inline]
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self {
            Self::IoError(err) => Some(err.as_ref()),
            Self::CorruptedData(_)
            | Self::DuplicateParent
            | Self::ExceededMaxSize(_)
            | Self::InvalidBlameRange
            | Self::InvalidEmail(_)
            | Self::InvalidHashLength(_)
            | Self::InvalidName(_)
            | Self::InvalidTimezoneOffset(_)
            | Self::InvalidTreeStructure(_)
            | Self::ObjectNotFound(_)
            | Self::Other(_)
            | Self::RefNotFound(_)
            | Self::SerializationError(_) => None,
        }
    }
}

impl PartialEq for VctrlError {
    #[inline]
    fn eq(&self, other: &Self) -> bool {
        match (self, other) {
            (Self::IoError(a), Self::IoError(b)) => {
                a.as_ref().kind() == b.as_ref().kind()
                    && a.as_ref().to_string() == b.as_ref().to_string()
            }
            (Self::DuplicateParent, Self::DuplicateParent)
            | (Self::InvalidBlameRange, Self::InvalidBlameRange) => true,
            (
                Self::CorruptedData(a)
                | Self::ExceededMaxSize(a)
                | Self::InvalidEmail(a)
                | Self::InvalidName(a)
                | Self::InvalidTreeStructure(a)
                | Self::Other(a)
                | Self::RefNotFound(a)
                | Self::SerializationError(a),
                Self::CorruptedData(b)
                | Self::ExceededMaxSize(b)
                | Self::InvalidEmail(b)
                | Self::InvalidName(b)
                | Self::InvalidTreeStructure(b)
                | Self::Other(b)
                | Self::RefNotFound(b)
                | Self::SerializationError(b),
            ) => a == b,
            (Self::InvalidHashLength(a), Self::InvalidHashLength(b)) => a == b,
            (Self::InvalidTimezoneOffset(a), Self::InvalidTimezoneOffset(b)) => a == b,
            (Self::ObjectNotFound(a), Self::ObjectNotFound(b)) => a == b,
            _ => false,
        }
    }
}

impl Eq for VctrlError {}

impl From<io::Error> for VctrlError {
    #[inline]
    fn from(err: io::Error) -> Self {
        Self::IoError(Arc::new(err))
    }
}

impl VctrlError {
    #[must_use]
    #[inline]
    pub fn from_io(err: io::Error) -> Self {
        Self::IoError(Arc::new(err))
    }
}