proc-macro-assertions 0.1.5

Easily create asserts on proc macro inputs
Documentation
/// Not meant to be called directly. Use [`assert_into!`] instead.
// TODO: Add differentiation for Ident / Type asserts added in 0.1.0 here as well
#[doc(hidden)]
#[macro_export]
macro_rules! internal_impl {
    // ======================= Trait Templates ======================================
    ($store:ident | $type:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(Trait::from_owned(parse_quote!($tokens)).test::<TokenCmpWrapper<syn::Type>>($type));
        }
    };
    ($store:ident | &$type:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(Trait::from_owned(parse_quote!($tokens)).test::<TokenCmpWrapper<syn::Type>>(&$type));
        }
    };
    ($store:ident | $type:ident with $generics:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(
                Trait::from_owned(parse_quote!($tokens))
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | $type:ident with &$generics:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(
                Trait::from_owned(parse_quote!($tokens))
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | &$type:ident with $generics:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(
                Trait::from_owned(parse_quote!($tokens))
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>(&$type),
            );
        }
    };
    ($store:ident | &$type:ident with &$generics:ident impl $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Trait;
            $store.assert(
                Trait::from_owned(parse_quote!($tokens))
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>(&$type),
            );
        }
    };

    // ======================= Type Templates without generics ======================
    ($store:ident | $type:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(Type::from_owned(parse_quote!($tokens), 0).test::<TokenCmpWrapper<syn::Type>>($type));
        }
    };
    ($store:ident | &$type:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(Type::from_owned(parse_quote!($tokens), 0).test::<TokenCmpWrapper<syn::Type>>(&$type));
        }
    };
    ($store:ident | $type:ident with $generics:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), 0)
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | $type:ident with &$generics:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), 0)
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | &$type:ident with $generics:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), 0)
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>(&$type),
            );
        }
    };
    ($store:ident | &$type:ident with &$generics:ident == $tokens:tt) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), 0)
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };

    // ======================= Type Templates with generics =========================
    ($store:ident | $type:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(Type::from_owned(parse_quote!($tokens), $num).test::<TokenCmpWrapper<syn::Type>>($type));
        }
    };
    ($store:ident | &$type:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(Type::from_owned(parse_quote!($tokens), $num).test::<TokenCmpWrapper<syn::Type>>(&$type));
        }
    };
    ($store:ident | $type:ident with $generics:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), $num)
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | $type:ident with &$generics:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), $num)
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>($type),
            );
        }
    };
    ($store:ident | &$type:ident with $generics:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), $num)
                    .with_generics::<TokenCmpWrapper<syn::Type>>($generics)
                    .test::<TokenCmpWrapper<syn::Type>>(&$type),
            );
        }
    };
    ($store:ident | &$type:ident with &$generics:ident == $tokens:tt<#$num:literal>) => {
        {
            internal_impl!(@internal imports);
            use $crate::generatable::Type;
            $store.assert(
                Type::from_owned(parse_quote!($tokens), $num)
                    .with_generics::<TokenCmpWrapper<syn::Type>>(&$generics)
                    .test::<TokenCmpWrapper<syn::Type>>(&$type),
            );
        }
    };

    // helper methods
    (@internal imports) => {
        #[allow(unused_imports)]
        use $crate::maybe_borrowed::FromMaybeBorrowed;
        use $crate::add_generics::AttachGenericsWithAssert;
        use $crate::assert::InsertIntoTemplate;
        use $crate::token_cmp_wrapper::TokenCmpWrapper;
        use syn::parse_quote;
    };
}

/// A macro that makes it easier to generate assertions into an assertion store
/// # Usage
/// ```
/// let store: proc_macro_assertions::store::Store = todo!();
/// let assertable = todo!() // For example syn::Ident or syn::Type depending on Template
///
/// // for [template dependant] see below in Template docs
/// assert_into!(store | assertable [template dependant]);
/// ```
/// There is also the option to pass `assertable` and `generics` (see below) by reference
/// ```
/// assert_into!(store | &assertable [template dependant]);
/// ```
/// # Generics
/// In case there is a need for generics to use `assertable` (assertable may be a `T` from the struct declaration)
/// you can pass generics using `with generics` in every macro kind.
/// ```
/// let generics: syn::Generics = todo!();
/// assert_into!(store | &assertable with &generics [template dependant]);
/// ```
/// # Templates supported
/// ## Trait (using `impl foo::Trait`)
/// A template that ensures that some `syn::Type` implements some trait.
/// ## Type (using `== foo::Type`)
/// A template that ensures that some `syn::Type` equals some other type.
/// ## Type with generics (using `== foo::Type<#[num]>` where `[num]` is the amount of Generics)
/// A template that ensures that some `syn::Type` equals some other type that accepts some generics.
/// # Examples
/// ## Trait
/// ```
/// let store: proc_macro_assertions::store::Store = todo!();
/// let assertable: syn::Type = todo!();
/// let generics: syn::Generics = todo!();
///
/// assert_into!(store | &assertable with &generics impl ::std::default::Default);
/// ```
/// The macro invocation will expand to (excluding automatic imports of used items) to something like
/// ```
/// store.assert(
///     Trait::from_owned(parse_quote!(::std::default::Default))
///         .with_generics(&generics)
///         .test(&assertable)
/// );
/// ```
/// ## Type
/// ```
/// let store: proc_macro_assertions::store::Store = todo!();
/// let assertable: syn::Type = todo!();
/// let generics: syn::Generics = todo!();
///
/// assert_into!(store | &assertable with &generics == String);
/// ```
/// The macro invocation will expand to (excluding automatic imports of used items) to something like
/// ```
/// store.assert(
///     Type::from_owned(parse_quote!(String), 0)
///         .with_generics(&generics)
///         .test(&assertable)
/// );
/// ```
#[macro_export]
macro_rules! assert_into {
    ( $($hidden:tt)* ) => {
        {
            use $crate::internal_impl;
            internal_impl!($($hidden)*);
        }
    };
}