dodo 0.3.1

Basic persistence library designed to be a quick and easy way to create a persistent storage.
Documentation
use std::{fmt, result};
use std::error::Error;

use crate::serializer::{SerializerError, SerializerErrorKind};
use crate::storage::{StorageError, StorageErrorKind};

/// Index error.
#[derive(Debug)]
pub struct IndexError(Box<RawIndexError>);

#[derive(Debug)]
struct RawIndexError {
    kind: IndexErrorKind,
    source: Option<Box<dyn std::error::Error + Send + Sync>>,
}

impl IndexError {
    pub(crate) fn not_found() -> Self {
        Self(Box::new(RawIndexError {
            kind: IndexErrorKind::NotFound,
            source: None,
        }))
    }

    pub(crate) fn syntax<E>(error: E) -> Self
        where E: Into<Box<dyn std::error::Error + Send + Sync>> {
        Self(Box::new(RawIndexError {
            kind: IndexErrorKind::Syntax,
            source: Some(error.into()),
        }))
    }

    pub(crate) fn storage_corrupted<E>(error: E) -> Self
        where E: Into<Box<dyn std::error::Error + Send + Sync>> {
        Self(Box::new(RawIndexError {
            kind: IndexErrorKind::StorageCorrupted,
            source: Some(error.into()),
        }))
    }

    pub(crate) fn io<E>(error: E) -> Self
        where E: Into<Box<dyn std::error::Error + Send + Sync>> {
        Self(Box::new(RawIndexError {
            kind: IndexErrorKind::Io,
            source: Some(error.into()),
        }))
    }

    pub(crate) fn other<E>(error: E) -> Self
        where E: Into<Box<dyn std::error::Error + Send + Sync>> {
        Self(Box::new(RawIndexError {
            kind: IndexErrorKind::Other,
            source: Some(error.into()),
        }))
    }

    /// Error kind.
    pub fn kind(&self) -> IndexErrorKind {
        self.0.kind
    }

    /// Returns true if this error is NotFound.
    pub fn is_not_found(&self) -> bool {
        IndexErrorKind::NotFound == self.0.kind
    }

    /// Returns true if this error a Syntax.
    pub fn is_syntax(&self) -> bool {
        IndexErrorKind::Syntax == self.0.kind
    }

    /// Returns true if this error a StorageCorrupted.
    pub fn is_storage_corrupted(&self) -> bool {
        IndexErrorKind::StorageCorrupted == self.0.kind
    }

    /// Returns true if this error Io.
    pub fn is_io(&self) -> bool {
        IndexErrorKind::Io == self.0.kind
    }

    /// Returns true if this error is Other.
    pub fn is_other(&self) -> bool {
        IndexErrorKind::Other == self.0.kind
    }
}

impl Error for IndexError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        match self.0.source {
            Some(ref source) => Some(&**source),
            None => None
        }
    }
}

impl fmt::Display for IndexError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.0.kind.fmt(f)
    }
}

impl From<StorageError> for IndexError {
    fn from(error: StorageError) -> Self {
        use StorageErrorKind::*;

        match error.kind() {
            InvalidUuid => Self::storage_corrupted(error),
            Io => Self::io(error),
            Other => Self::other(error),
            NotFound => panic!("index file not found"),
        }
    }
}

impl From<SerializerError> for IndexError {
    fn from(error: SerializerError) -> Self {
        use SerializerErrorKind::*;

        match error.kind() {
            Syntax => Self::syntax(error),
            Io => Self::io(error),
            Other => Self::other(error)
        }
    }
}

/// Index error kind.
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum IndexErrorKind {
    /// Value not found in index.
    NotFound,
    /// Serialization/deserialization error.
    Syntax,
    /// Storage is in an invalid state and cannot perform the requested operation.
    StorageCorrupted,
    /// Io error (unexpected EOF, interrupted, ...).
    Io,
    /// Other error.
    Other,
}

impl fmt::Display for IndexErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        use IndexErrorKind::*;

        match self {
            NotFound => write!(f, "value not found"),
            Syntax => write!(f, "serialization/deserialization error"),
            StorageCorrupted => write!(f, "storage is corrupted"),
            Io => write!(f, "io error"),
            Other => write!(f, "other error"),
        }
    }
}

/// Index result.
pub type Result<T> = result::Result<T, IndexError>;