proc-macro-assertions 0.1.5

Easily create asserts on proc macro inputs
Documentation
mod r#trait;
mod r#type;

use std::hash::Hash;
use std::ops::{Deref, DerefMut};

use better_any::{Tid, TidAble};
use quote::ToTokens;
pub use r#trait::Trait;
pub use r#type::Type;

use proc_macro2::TokenStream;

use crate::maybe_borrowed::MaybeBorrowed;

use super::{context::Context, passed_data::PassedData};

/// This indicates that some type can be turned into tokens that assert something.
/// Be aware that this only relies on rust's type checking, the code that is generated
/// is never actually meant to be executed. The generation functions in three distinct "Stages".
/// See below for more information on that.
///
///
/// The type implementing this must also be [`TidAble`], which is similar to [`Any`](std::any::Any)
/// but allows for non-'static lifetimes. The easiest way to implement it is to use the derive macro (`#[derive(Tid)]`)
///
/// # Idents
/// There is a need to ensure that there are no ident collisions among the generated code.
/// For that purpose in each stage there is a context provided, which contains some [`IdentGenerator`](crate::ident_generator::IdentGenerator).
/// Other than Idents passed into the methods by either `Self` or any parameters, use Idents generates by the `IdentGenerator`
/// exclusively to avoid any collisions.
///
/// # Generation "Stages"
/// ## Stage 1: Generatable
/// These tokens are generated for each type that implemets this trait once. This is the perfect place to put
/// tokens that are needed as "Setup" for any asserts.
/// ## Stage 2: Template
/// These tokens are generated for each unique instance of `Self`. You should put any tokens that should be unique
/// for each instance in here.
/// ## Stage 3: Assert
/// These tokens are generated for each unique Assert, which represent some type that is tested against `Self`.
/// No generation is actually happening until at least one assert is created for `Self`.
///
/// # Passed Data
/// There may be a need to pass data, for example generated idents, between stages. For that purpose
/// this trait provides a way to do so. See [`PassedData`](crate::passed_data::PassedData) for more information.
pub trait Generatable<'a, Assert>
where
    Self: TidAble<'a>,
    Assert: 'a + TidAble<'a>,
{
    /// The type of any data passed from the `Generatable` stage to proceeding stages.
    type GeneratableData: 'a;
    /// The type of any data passed from the `Template` stage to proceeding stages.
    type TemplateData: 'a;

    /// Set this to true when any of the emitted code may be non-constant
    const EMITS_NON_CONSTANT_CODE: bool;

    /// This is the method the `Generatable` stage is composed of. Should return Tokens (if any) generated by this stage,
    /// plus optionally any data passed to preceding stages.
    fn generatable(context: &mut Context) -> PassedData<Self::GeneratableData>
    where
        Self: Sized;

    /// This is the method the `Template` stage is composed of. Should return Tokens (if any) generated by this stage,
    /// plus optionally any data passed to preceding stages.
    fn template(
        &self,
        context: &mut Context,
        passed: &Self::GeneratableData,
    ) -> PassedData<Self::TemplateData>;

    /// This is the method the `Assert` stage is composed of. Should return Tokens generated by this stage.
    fn assert(
        &self,
        _context: &mut Context,
        _passed: (&Self::GeneratableData, &Self::TemplateData),
        _to_assert: &Assert,
    ) -> Option<TokenStream>;
}

#[derive(Tid)]
#[repr(transparent)]
pub struct StaticTid<T: 'static>(pub T);

impl<T: 'static> From<T> for StaticTid<T> {
    fn from(value: T) -> Self {
        Self(value)
    }
}

impl<'a, T> From<&'a T> for &'a StaticTid<T> {
    fn from(value: &'a T) -> Self {
        // Safe because StaticTid is #[repr(transparent)].
        unsafe { &*(value as *const T).cast::<StaticTid<T>>() }
    }
}

impl<'a, T> From<&'a mut T> for &'a mut StaticTid<T> {
    fn from(value: &'a mut T) -> Self {
        // Safe because StaticTid is #[repr(transparent)].
        unsafe { &mut *(value as *mut T).cast::<StaticTid<T>>() }
    }
}

impl<'a, U> From<&'a U> for MaybeBorrowed<'a, StaticTid<U>> {
    fn from(value: &'a U) -> Self {
        MaybeBorrowed::Borrowed(value.into())
    }
}

impl<'a, T> From<T> for MaybeBorrowed<'a, StaticTid<T>> {
    fn from(value: T) -> Self {
        MaybeBorrowed::Owned(StaticTid(value))
    }
}
impl<T: 'static> Deref for StaticTid<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl<T: 'static> DerefMut for StaticTid<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

impl<T: 'static + ToTokens> ToTokens for StaticTid<T> {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        (**self).to_tokens(tokens);
    }
}

impl<T: 'static + PartialEq> PartialEq for StaticTid<T> {
    fn eq(&self, other: &Self) -> bool {
        (**self).eq(&**other)
    }
}

impl<T: 'static + Eq> Eq for StaticTid<T> {}

impl<T: 'static + PartialOrd> PartialOrd for StaticTid<T> {
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        (**self).partial_cmp(&**other)
    }
}

impl<T: 'static + Ord> Ord for StaticTid<T> {
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        (**self).cmp(&**other)
    }
}

impl<T: 'static + Hash> Hash for StaticTid<T> {
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
        (**self).hash(state);
    }
}