use std::marker::PhantomData;
use crate::{
assertable::Assertable, maybe_borrowed::MaybeBorrowed, raw_assert::r#trait::RawAssertable,
};
pub trait AssertableWithBounds<'a, T> {
type Output: RawAssertable<'a>;
fn do_assert(&self, bounds: T) -> Self::Output;
}
impl<'a, T, U> AssertableWithBounds<'a, T> for &'a U
where
U: AssertableWithBounds<'a, T>,
{
type Output = U::Output;
fn do_assert(&self, bounds: T) -> Self::Output {
(*self).do_assert(bounds)
}
}
pub struct ResolvedBounds<'a, T, U>
where
U: AssertableWithBounds<'a, T>,
{
bounds: T,
assertable: MaybeBorrowed<'a, U>,
_lt: PhantomData<&'a ()>,
}
impl<'a, T, U> ResolvedBounds<'a, T, U>
where
U: AssertableWithBounds<'a, T>,
{
fn new(bounds: T, assertable: MaybeBorrowed<'a, U>) -> Self {
Self {
bounds,
assertable,
_lt: PhantomData,
}
}
}
impl<'a, T, U> Assertable<'a> for ResolvedBounds<'a, T, U>
where
U: AssertableWithBounds<'a, T>,
{
type Output = <U as AssertableWithBounds<'a, T>>::Output;
fn do_assert(self) -> Self::Output {
self.assertable.do_assert(self.bounds)
}
}
pub trait ProvideBounds<'a, T>
where
Self: Sized + AssertableWithBounds<'a, T>,
{
fn provide_bounds(self, bounds: T) -> ResolvedBounds<'a, T, Self>;
}
impl<'a, T, U> ProvideBounds<'a, T> for U
where
U: Sized + AssertableWithBounds<'a, T>,
{
fn provide_bounds(self, bounds: T) -> ResolvedBounds<'a, T, Self> {
ResolvedBounds::new(bounds, self.into())
}
}
pub trait ResolveBounds<'a, T>
where
Self: Sized,
T: Sized + AssertableWithBounds<'a, Self> + 'a,
{
fn resolve_for(
self,
assertable: impl Into<MaybeBorrowed<'a, T>>,
) -> ResolvedBounds<'a, Self, T>;
}
impl<'a, T, U> ResolveBounds<'a, T> for U
where
T: Sized + AssertableWithBounds<'a, Self> + 'a,
Self: Sized,
{
fn resolve_for(
self,
assertable: impl Into<MaybeBorrowed<'a, T>>,
) -> ResolvedBounds<'a, Self, T> {
ResolvedBounds::new(self, assertable.into())
}
}