mod want_one;
use core::marker::PhantomData;
pub use want_one::WantOne;
use crate::erased_wide::MutErasedWide;
use crate::lt_list::{Cons, Hole, Lt0, Lt1, LtList};
use crate::tag::{ReifySized, Tag, TagTypeId, Tagged, WithLt};
pub trait Want<L: LtList = Lt0> {
fn try_for_id(&mut self, tag_type_id: TagTypeId<L>) -> Option<ErasedWantFor<'_, 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::UsedTag>,
) -> ErasedWantFor<'u, L> {
ErasedWantFor {
erased: MutErasedWide::<'u, Lt1<'u, L>>::new::<DynWantFor<T::UsedTag>>(want_for),
}
}
pub fn downcast<T: ?Sized + ReifySized<L>>(
self,
) -> Result<&'u mut dyn WantFor<T::Lifetimes, T::UsedTag>, Self> {
self.erased
.downcast::<DynWantFor<T::UsedTag>>()
.map_err(|erased| Self { erased })
}
}
impl<'u, L: LtList> dyn Want<L> + 'u {
pub fn provide_value<T>(&mut self, value: T) -> &mut Self
where
T: ReifySized<L, SizedReified = T>,
{
if let Some(want) = self.try_for::<T>() {
want.fulfill(value);
}
self
}
pub fn provide_tag<T: ?Sized + ReifySized<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<L>,
F: FnOnce() -> <T as ReifySized<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<L>,
F: FnOnce(C) -> <T as ReifySized<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<L>>(
&mut self,
) -> Option<&mut dyn WantFor<T::Lifetimes, T::UsedTag>> {
let erased = self.try_for_id(TagTypeId::<L>::of::<T>())?;
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 = Cons<Hole, T::LifetimesTag>;
}