//! Protocol for giving a hint to a walker.
//!
//! Sometimes a walker has multiple protocols it could use,
//! this module gives a protocol by which a visitor can give a hint
//! to the walker about what it is expecting.
use crate::{
any::TypeName,
effect::{Effect, Future},
higher_ranked_trait, higher_ranked_type,
hkt::Marker,
protocol::Visitor,
Flow,
};
higher_ranked_trait! {
pub type class HintKnown for<'a, 'ctx> {
type Bound = &'a &'ctx ();
type T: { Send + Sized } where { 'ctx: 'a };
type HigherRanked: { };
}
}
/// Meta information for the hint.
///
/// This gives the visitor more information to work from when selecting a hint.
pub trait HintMeta: Send + Sync + 'static {
/// Information known by the walker.
///
/// This should be information easy to get without changing the state of the walker
/// in an irreversible way.
type Known: HintKnown::MemberType;
/// Extra information the visitor can give to the walker about what it is expecting.
type Hint;
}
pub type Known<'a, 'ctx, Protocol> = HintKnown::T<'a, 'ctx, <Protocol as HintMeta>::Known>;
/// Object implementing the [`Hint`] protocol.
pub trait Hint<'ctx, Protocol: ?Sized + HintMeta, E: Effect> {
/// Hint to the walker to use the `P` protocol.
///
/// This should only be called once per [`RequestHint`].
fn hint<'a>(
&'a mut self,
visitor: Visitor<'a, 'ctx>,
hint: <Protocol as HintMeta>::Hint,
) -> Future<'a, Flow, E>;
/// Ask the walker for information about it's support of the protocol.
fn known<'a>(
&'a mut self,
hint: &'a <Protocol as HintMeta>::Hint,
) -> Future<'a, Result<Known<'a, 'ctx, Protocol>, ()>, E>;
}
pub struct HintProto<Protocol: ?Sized, E: Effect>(Marker<(*const Protocol, E)>);
higher_ranked_type! {
impl TypeName {
impl['a, 'ctx, Protocol, E] type T['a, 'ctx] for HintProto<Protocol, E> =
dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a
where {
Protocol: 'static,
E: Effect
};
impl['a, 'ctx, Protocol, E] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol, E> + Send + Sync + 'a =
HintProto<Protocol, E>
where {
Protocol: 'static,
E: Effect,
};
}
}
// #[cfg(test)]
// mod test {
// use crate::{
// effect::{BlockOn, Blocking, Spin},
// };
//
// use super::*;
//
// #[test]
// fn demo() {
// struct X<'ctx>(&'ctx mut i32);
//
// #[derive(Debug)]
// struct Y;
//
// bijective_higher_ranked_type! {
// type DynY['ctx][]: WithContextLt['ctx][] for<'a> (Y)
// }
//
// bijective_higher_ranked_type! {
// type [][]: TypeName[][] for<'ctx> (DynY<'ctx>)
// }
//
// impl<'ctx, E: Effect<'ctx>> Hint<'ctx, DynY<'ctx>, E> for X<'ctx> {
// fn hint<'a>(
// &'a mut self,
// _visitor: Visitor<'a, 'ctx>,
// _hint: <DynY<'ctx> as HintMeta<'ctx>>::Hint,
// ) -> Future<'a, 'ctx, Flow, E> {
// todo!()
// }
//
// fn known<'a>(
// &'a mut self,
// _hint: &'a <DynY<'ctx> as HintMeta<'ctx>>::Hint,
// ) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, DynY<'ctx>>, ()>, E> {
// E::ready(Ok(&mut *self.0))
// }
// }
//
// higher_ranked_type! {
// type KnownHkt['ctx]: (AnySend) = for<'lt> &'lt mut i32
// }
//
// impl<'ctx> HintMeta<'ctx> for DynY<'ctx> {
// type Known = KnownHkt<'ctx>;
//
// type Hint = ();
// }
//
// let mut z = 42;
// let mut x = X(&mut z);
// let y: &mut WithContextLt::T<'_, '_, DynHint<'_, DynY<'_>, Blocking>> = &mut x;
//
// fn id<'a, 'ctx, T: ?Sized + TypeName::LowerType<'ctx>>(_x: &WithContextLt::T<'a, 'ctx, T>) {
// }
// id::<DynHint<'_, DynY<'_>, Blocking>>(y);
//
// let x = Spin::block_on(y.known(&()));
// match x {
// Ok(value) => *value += 1,
// Err(_) => todo!(),
// }
// assert_eq!(z, 43);
// }
// }