proc-macro-assertions 0.1.5

Easily create asserts on proc macro inputs
Documentation
use std::hash::Hash;
use std::ops::Deref;

use better_any::{Tid, TidAble};
use quote::ToTokens;

/// Some type that is eiher borrowed or owned
#[derive(Debug, Tid)]
pub enum MaybeBorrowed<'a, T> {
    /// Some borrowed type
    Borrowed(&'a T),
    /// Some owned type
    Owned(T),
}

impl<'a, T> ToTokens for MaybeBorrowed<'a, T>
where
    T: ToTokens,
{
    fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
        (**self).to_tokens(tokens);
    }

    fn to_token_stream(&self) -> proc_macro2::TokenStream {
        (**self).to_token_stream()
    }

    fn into_token_stream(self) -> proc_macro2::TokenStream
    where
        Self: Sized,
    {
        self.to_token_stream()
    }
}

impl<'a, T> PartialEq for MaybeBorrowed<'a, T>
where
    T: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        PartialEq::eq(&**self, &**other)
    }
}

impl<'a, T> Eq for MaybeBorrowed<'a, T> where T: Eq {}

impl<'a, T> PartialOrd for MaybeBorrowed<'a, T>
where
    T: PartialOrd,
{
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
        PartialOrd::partial_cmp(&**self, &**other)
    }
}

impl<'a, T> Ord for MaybeBorrowed<'a, T>
where
    T: Ord,
{
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
        Ord::cmp(&**self, &**other)
    }
}

impl<'a, T> MaybeBorrowed<'a, T> {
    /// Check if `Self` contains a borrowed type
    /// Inverse of [`MaybeBorrowed::is_owned`].
    pub const fn is_borrowed(&self) -> bool {
        match self {
            Self::Borrowed(_) => true,
            Self::Owned(_) => false,
        }
    }

    /// Check if `Self` contains a owned type.
    /// Inverse of [`MaybeBorrowed::is_borrowed`].
    pub const fn is_owned(&self) -> bool {
        !self.is_borrowed()
    }
}

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

impl<'a, T> Deref for MaybeBorrowed<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        match self {
            MaybeBorrowed::Borrowed(val) => val,
            MaybeBorrowed::Owned(ref val) => val,
        }
    }
}

impl<'a, T> From<T> for MaybeBorrowed<'a, T> {
    fn from(value: T) -> Self {
        Self::Owned(value)
    }
}

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

#[allow(clippy::module_name_repetitions)]
pub trait FromMaybeBorrowed<'a, T: 'a> {
    fn from_maybe_borrowed(from: MaybeBorrowed<'a, T>) -> Self;

    fn from_owned(from: T) -> Self
    where
        Self: Sized,
    {
        Self::from_maybe_borrowed(from.into())
    }

    fn from_borrowed(from: &'a T) -> Self
    where
        Self: Sized,
    {
        Self::from_maybe_borrowed(from.into())
    }
}

#[cfg(test)]
mod test {
    use super::MaybeBorrowed;

    #[test]
    fn is_borrowed() {
        let test_data = String::from("Test Data");
        let maybe_borrowed: MaybeBorrowed<String> = (&test_data).into();

        assert!(maybe_borrowed.is_borrowed());
        assert!(!maybe_borrowed.is_owned());
    }

    #[test]
    fn is_owned() {
        let test_data = String::from("Test Data");
        let maybe_borrowed: MaybeBorrowed<String> = test_data.into();

        assert!(!maybe_borrowed.is_borrowed());
        assert!(maybe_borrowed.is_owned());
    }

    #[test]
    fn from_reference() {
        let test_data = String::from("Test Data");
        let maybe_borrowed: MaybeBorrowed<String> = (&test_data).into();

        assert_eq!(maybe_borrowed, MaybeBorrowed::Borrowed(&test_data));
    }

    #[test]
    fn from_owned() {
        let test_data = String::from("Test Data");
        let maybe_borrowed: MaybeBorrowed<String> = test_data.clone().into();

        assert_eq!(maybe_borrowed, MaybeBorrowed::Owned(test_data));
    }
}