use better_any::TidAble;
use crate::{
assert::Assert, assertable::Assertable, generatable::Generatable, into_template::TypeEq,
maybe_borrowed::MaybeBorrowed, raw_assert::RawAssert,
};
pub struct WithGenerics<'a, T> {
pub data: T,
pub generics: Option<MaybeBorrowed<'a, syn::Generics>>,
}
pub trait AttachGenerics<'a> {
type Output;
fn with_generics<G>(self, generics: G) -> WithGenerics<'a, Self::Output>
where
G: Into<MaybeBorrowed<'a, syn::Generics>>,
Self: Sized,
{
self.with_optional_generics(Some(generics))
}
fn with_optional_generics<G>(self, generics: Option<G>) -> WithGenerics<'a, Self::Output>
where
G: Into<MaybeBorrowed<'a, syn::Generics>>;
}
pub trait AttachGenericsWithAssert<'a, A> {
type Output;
fn with_generics<B>(
self,
generics: impl Into<MaybeBorrowed<'a, syn::Generics>>,
) -> WithGenerics<'a, Self::Output>
where
B: TypeEq<This = A>,
Self: Sized,
{
self.with_optional_generics::<B>(Some(generics))
}
fn with_optional_generics<B>(
self,
generics: Option<impl Into<MaybeBorrowed<'a, syn::Generics>>>,
) -> WithGenerics<'a, Self::Output>
where
B: TypeEq<This = A>;
}
impl<'a, Gen, A> AttachGenericsWithAssert<'a, A> for Gen
where
Gen: Generatable<'a, A>,
A: 'a + TidAble<'a>,
{
type Output = MaybeBorrowed<'a, Self>;
fn with_optional_generics<B>(
self,
generics: Option<impl Into<MaybeBorrowed<'a, syn::Generics>>>,
) -> WithGenerics<'a, Self::Output>
where
B: TypeEq<This = A>,
{
WithGenerics {
data: self.into(),
generics: generics.map(Into::into),
}
}
}
impl<'a, Gen> AttachGenerics<'a> for MaybeBorrowed<'a, Gen> {
type Output = MaybeBorrowed<'a, Gen>;
fn with_optional_generics<G>(self, generics: Option<G>) -> WithGenerics<'a, Self::Output>
where
G: Into<MaybeBorrowed<'a, syn::Generics>>,
{
WithGenerics {
data: self,
generics: generics.map(Into::into),
}
}
}
impl<'a, Gen, A> AttachGenerics<'a> for Assert<'a, Gen, A>
where
Gen: Generatable<'a, A>,
A: 'a + TidAble<'a>,
{
type Output = Assert<'a, Gen, A>;
fn with_optional_generics<G>(self, generics: Option<G>) -> WithGenerics<'a, Self::Output>
where
G: Into<MaybeBorrowed<'a, syn::Generics>>,
{
WithGenerics {
data: self,
generics: generics.map(Into::into),
}
}
}
impl<'a, G, A> Assertable<'a> for WithGenerics<'a, Assert<'a, G, A>>
where
G: Generatable<'a, A> + Eq + Ord,
A: Eq + Ord + TidAble<'a>,
{
type Output = RawAssert<'a, G, A>;
fn do_assert(self) -> RawAssert<'a, G, A> {
RawAssert {
template: self.data.template,
generics: check_generics(self.generics),
assert: self.data.assert,
}
}
}
fn check_generics(
generics: Option<MaybeBorrowed<syn::Generics>>,
) -> Option<MaybeBorrowed<syn::Generics>> {
generics.and_then(|f| {
if f.lt_token.is_some()
&& f.gt_token.is_some()
&& !f.params.is_empty()
&& f.where_clause
.as_ref()
.is_some_and(|w| !w.predicates.is_empty())
{
Some(f)
} else {
None
}
})
}