use crate::{
assert::Assert, assertable::Assertable, generatable::Generatable,
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>>;
}
impl<'a, Gen> AttachGenerics<'a> for Gen
where
Gen: Generatable<'a>,
{
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: MaybeBorrowed::Owned(self),
generics: generics.map(Into::into),
}
}
}
impl<'a, Gen> AttachGenerics<'a> for MaybeBorrowed<'a, Gen>
where
Gen: Generatable<'a>,
{
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> AttachGenerics<'a> for Assert<'a, Gen>
where
Gen: Generatable<'a>,
{
type Output = Assert<'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, G> Assertable<'a> for WithGenerics<'a, Assert<'a, G>>
where
G: Generatable<'a> + Eq + Ord,
G::Assert: Eq + Ord,
{
type Output = RawAssert<'a, G>;
fn do_assert(self) -> RawAssert<'a, G> {
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
}
})
}