mod want_one;
use core::marker::PhantomData;
pub use want_one::WantOne;
use crate::erased_wide::MutErasedWide;
use crate::lt_list::EmptyLt;
use crate::tag::{ReifySized, Tag, TagTypeId, Tagged, WithLt};
use crate::{Lt0, Lt1, LtList};
pub trait Want<'r, L: LtList = Lt0> {
fn try_for_id(
&mut self,
tag_type_id: TagTypeId<Lt1<'r, L>>,
) -> Option<ErasedWantFor<'_, Lt1<'r, L>>>;
fn is_satisfied(&self) -> bool;
}
pub trait WantFor<L: LtList, T: ?Sized + ReifySized<L>> {
fn fulfill(&mut self, value: T::Reified);
fn is_satisfied(&self) -> bool;
}
pub struct ErasedWantFor<'u, L: LtList> {
erased: MutErasedWide<'u, Lt1<'u, L>>,
}
impl<'u, L: LtList> ErasedWantFor<'u, L> {
pub fn new<T: ?Sized + ReifySized<L>>(
want_for: &'u mut dyn WantFor<T::Lifetimes, T::Tag>,
) -> ErasedWantFor<'u, L> {
ErasedWantFor {
erased: MutErasedWide::<'u, Lt1<'u, L>>::new::<DynWantFor<T::Tag>, Lt1<'u, T::Lifetimes>>(
want_for,
),
}
}
pub fn downcast<T: ?Sized + ReifySized<L>>(
self,
) -> Result<&'u mut dyn WantFor<T::Lifetimes, T::Tag>, Self> {
self.erased
.downcast::<DynWantFor<T::Tag>, Lt1<'u, T::Lifetimes>>()
.map_err(|erased| Self { erased })
}
}
impl<'u, 'r, L: LtList> dyn Want<'r, L> + 'u {
pub fn provide_value<T>(&mut self, value: T) -> &mut Self
where
T: ReifySized<Lt1<'r, L>, SizedReified = T>,
{
if let Some(want) = self.try_for::<T>() {
want.fulfill(value);
}
self
}
pub fn provide_tag<T: ?Sized + ReifySized<Lt1<'r, L>>>(
&mut self,
value: T::Reified,
) -> &mut Self {
if let Some(want) = self.try_for::<T>() {
want.fulfill(value);
}
self
}
pub fn provide<T, F>(&mut self, f: F) -> &mut Self
where
T: ReifySized<Lt1<'r, L>>,
F: FnOnce() -> <T as ReifySized<Lt1<'r, L>>>::SizedReified,
{
if let Some(want) = self.try_for::<T>() {
want.fulfill(f());
}
self
}
pub fn provide_with<T, C, F>(&mut self, ctx: C, f: F) -> Option<C>
where
T: ReifySized<Lt1<'r, L>>,
F: FnOnce(C) -> <T as ReifySized<Lt1<'r, L>>>::SizedReified,
{
if let Some(want) = self.try_for::<T>() {
want.fulfill(f(ctx));
None
} else {
Some(ctx)
}
}
pub fn try_for<T: ?Sized + ReifySized<Lt1<'r, L>>>(
&mut self,
) -> Option<&mut dyn WantFor<T::Lifetimes, T::Tag>> {
let erased = self.try_for_id(TagTypeId::<Lt1<'r, L>>::of::<T::Tag, T::Lifetimes>())?;
erased.downcast::<T>().ok()
}
}
struct DynWantFor<T: ?Sized>(PhantomData<fn() -> *const T>);
impl<'u, T: ?Sized + WithLt<L>, L: LtList> WithLt<Lt1<'u, L>> for DynWantFor<T> {
type Reified = dyn WantFor<L, T> + 'u;
}
impl<T: ?Sized + Tagged + 'static> Tagged for DynWantFor<T> {
type Tag = DynWantFor<T::Tag>;
}
impl<T: ?Sized + Tag + 'static> Tag for DynWantFor<T> {
type LifetimesTag = EmptyLt<T::LifetimesTag>;
}