dbstruct-derive 0.4.0

Build a typed database by defining a struct
Documentation
use core::fmt;
use proc_macro2::{Span, TokenTree};

use crate::errors::Help;
use crate::GetSpan;

#[derive(Debug, thiserror::Error)]
pub enum ErrorVariant {
    #[error("no database backend specified")]
    MissingDb,
    #[error("backend option has no value set")]
    MissingBackendValue,
    #[error("incorrect syntax for backend")]
    InvalidBackendSyntax,
    #[error("not a known dbstruct option")]
    NotAnOption(proc_macro2::Ident),
    #[error("invalid syntax for dbstruct option")]
    InvalidSyntax(TokenTree),
    #[error("Not a known database backend: `{0}`")]
    NotABackend(proc_macro2::Ident),
}

#[derive(thiserror::Error, Debug)]
pub struct Error {
    variant: ErrorVariant,
    span: Option<Span>,
}

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

impl Help for Error {
    fn help(&self) -> Option<String> {
        use ErrorVariant::*;
        Some(match self.variant {
            MissingDb => "try specifying an db, for example: `db=sled`",
            MissingBackendValue => "try setting a supported backend, for example `db=sled`",
            InvalidBackendSyntax => "a backend should be a single world not enclosed in \"",
            NotAnOption(_) => "the only supported option currently is: db",
            InvalidSyntax(_) => "the option should be a single word not enclosed in \"",
            NotABackend(_) => "try sled as database backend",
        }.to_owned())
    }
}

impl Error {
    pub fn span(&self) -> Span {
        use ErrorVariant::*;
        match (&self.variant, self.span) {
            (NotAnOption(item), None) => item.span(),
            (InvalidSyntax(item), None) => item.span(),
            (NotABackend(item), None) => item.span(),
            (_, Some(span)) => span,
            (_var, _) => unreachable!(
                "error should track a span for {_var:?} as 
                the variant itself does not contain one"
            ),
        }
    }
}

impl ErrorVariant {
    pub(super) fn with_span(self, item: impl GetSpan) -> Error {
        Error {
            variant: self,
            span: Some(item.span()),
        }
    }

    pub(super) fn has_span(self) -> Error {
        Error {
            variant: self,
            span: None,
        }
    }
}