//! 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 core::ops::ControlFlow;
use crate::{
any::{TypeName, TypeNameable},
effect::{Effect, Future},
hkt::AnySend,
nameable,
protocol::Visitor,
Flow,
};
/// Meta information for the hint.
///
/// This gives the visitor more information to work from when selecting a hint.
pub trait HintMeta<'ctx> {
/// 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: AnySend::Trait<'ctx>;
/// Extra information the visitor can give to the walker about what it is expecting.
type Hint;
}
pub type Known<'a, 'ctx, Protocol> = AnySend::T<'a, 'ctx, <Protocol as HintMeta<'ctx>>::Known>;
/// Object implementing the [`Hint`] protocol.
pub trait Hint<'a, 'ctx: 'a, Protocol: ?Sized + HintMeta<'ctx>, E: Effect<'ctx>> {
/// Hint to the walker to use the `P` protocol.
///
/// This should only be called once per [`RequestHint`].
fn hint(
&'a mut self,
visitor: Visitor<'a, 'ctx>,
hint: <Protocol as HintMeta<'ctx>>::Hint,
) -> Future<'a, 'ctx, Flow, E>;
/// Ask the walker for information about it's support of the protocol.
fn known(
&'a mut self,
hint: &'a <Protocol as HintMeta<'ctx>>::Hint,
) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, Protocol>, ()>, E>;
}
pub type DynHint<'a, 'ctx, Protocol, E> = dyn Hint<'a, 'ctx, Protocol, E> + Send + 'a;
nameable! {
pub struct Name['ctx, Protocol, E] for<'a>;
impl [Protocol::Name, E] for DynHint<'a, 'ctx, Protocol, E> where {
Protocol: TypeNameable<'ctx> + ?Sized,
E: Effect<'ctx>,
}
impl [Protocol, E] where DynHint<'a, 'ctx, Protocol::Nameable, E> {
Protocol: TypeName<'ctx> + ?Sized,
E: Effect<'ctx>,
}
}
#[cfg(test)]
mod test {
use core::ops::ControlFlow;
use crate::{
any::TypeNameable,
effect::{BlockOn, Blocking, Spin},
higher_ranked_type,
};
use super::*;
#[test]
fn demo() {
struct X<'ctx>(&'ctx mut i32);
#[derive(Debug)]
struct Y;
nameable! {
struct Name['a, 'ctx];
impl for Y where {}
}
impl<'a, 'ctx: 'a, E: Effect<'ctx>> Hint<'a, 'ctx, Y, E> for X<'ctx> {
fn hint(
&'a mut self,
_visitor: Visitor<'a, 'ctx>,
_hint: <Y as HintMeta<'ctx>>::Hint,
) -> Future<'a, 'ctx, Flow, E> {
todo!()
}
fn known(
&'a mut self,
_hint: &'a <Y as HintMeta<'ctx>>::Hint,
) -> Future<'a, 'ctx, Result<Known<'a, 'ctx, Y>, ()>, E> {
E::ready(Ok(&mut *self.0))
}
}
higher_ranked_type! {
type KnownHkt['ctx]: (AnySend) = for<'lt> &'lt mut i32
}
impl<'ctx> HintMeta<'ctx> for Y {
type Known = KnownHkt<'ctx>;
type Hint = ();
}
let mut z = 42;
let mut x = X(&mut z);
let y: &mut DynHint<'_, '_, Y, Blocking> = &mut x;
fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(_x: &T) {}
id(y);
let x = Spin::block_on(y.known(&()));
match x {
Ok(value) => *value += 1,
Err(_) => todo!(),
}
assert_eq!(z, 43);
}
}