oxidate 0.1.0

Turns strings into a Rust AST
Documentation
pub mod assertions;

use crate::{
    coerce::compile_error::{CompileError, ToCompileError},
    error::assertions::{
        AssertionFailureExpected, AssertionFailureProperty, DiagnosticError, Property,
    },
    macro_error, Span, Tokens,
};

#[derive(Debug, Clone, thiserror::Error)]
#[error("{reason}")]
pub struct CustomCompileError {
    pub span: Span,
    pub reason: String,
}

impl CompileError for CustomCompileError {
    fn into_compile_error(self) -> Tokens {
        let Self { span, reason } = self;

        macro_error!(display(reason) spanned span)
    }
}

#[derive(Debug, thiserror::Error)]
#[error("{error}")]
pub struct MissingCrate {
    error: proc_macro_crate::Error,
}

impl From<proc_macro_crate::Error> for MissingCrate {
    fn from(error: proc_macro_crate::Error) -> Self {
        MissingCrate { error }
    }
}

impl CompileError for MissingCrate {
    fn into_compile_error(self) -> Tokens {
        self.to_compile_error()
    }
}

impl ToCompileError for MissingCrate {
    fn to_compile_error(&self) -> Tokens {
        match &self.error {
            proc_macro_crate::Error::NotFound(path) => macro_error!(format(
                "Could not find `Cargo.toml` in manifest dir: `{}`.",
                path.display()
            )),
            proc_macro_crate::Error::CargoManifestDirNotSet => {
                macro_error!("`CARGO_MANIFEST_DIR` env variable not set.")
            }
            proc_macro_crate::Error::CouldNotRead { path, .. } => {
                macro_error!(format("Could not read `{}`.", path.display()))
            }
            proc_macro_crate::Error::InvalidToml { source } => {
                macro_error!(format("Invalid Cargo.toml: {}", source))
            }
            proc_macro_crate::Error::CrateNotFound { crate_name, path } => macro_error!(format(
                "Could not find `{}` in `dependencies` or `dev-dependencies` in `{}`!",
                crate_name,
                path.display()
            )),
        }
    }
}

#[derive(Debug, thiserror::Error)]
pub enum MacroError {
    #[error("{0}")]
    MissingCrate(#[from] MissingCrate),
    #[error("{0}")]
    Diagnostic(#[from] DiagnosticError),
    #[error("{0}")]
    Custom(#[from] CustomCompileError),
}

impl MacroError {
    pub fn expected(expected: impl Into<String>) -> AssertionFailureExpected {
        DiagnosticError::expected(expected)
    }

    pub fn expected_property(property: impl Into<Property>) -> AssertionFailureProperty {
        DiagnosticError::expected_property(property)
    }

    pub fn compile_error(span: impl Into<Span>, reason: impl Into<String>) -> MacroError {
        MacroError::Custom(CustomCompileError {
            span: span.into(),
            reason: reason.into(),
        })
    }

    pub fn to_compile_error(&self) -> Tokens {
        match self {
            MacroError::Custom(custom) => custom.to_compile_error(),
            MacroError::MissingCrate(missing) => missing.to_compile_error(),
            MacroError::Diagnostic(assertion) => assertion.to_compile_error(),
        }
    }
}

pub type MacroResult<T> = Result<T, MacroError>;