Diffstat (limited to 'src/protocol/walker/hint.rs')
-rw-r--r--src/protocol/walker/hint.rs65
1 files changed, 57 insertions, 8 deletions
diff --git a/src/protocol/walker/hint.rs b/src/protocol/walker/hint.rs
index 683436a..049d881 100644
--- a/src/protocol/walker/hint.rs
+++ b/src/protocol/walker/hint.rs
@@ -4,11 +4,13 @@
//! this module gives a protocol by which a visitor can give a hint
//! to the walker about what it is expecting.
+use core::ops::{Deref, DerefMut};
+
use crate::{
- any::TypeName,
- effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _},
+ any::{AnyTrait, TypeName},
+ effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _, Ss},
hkt::Marker,
- protocol::{visitor::VisitResult, DynWalker},
+ protocol::{visitor::VisitResult, DynVisitor, DynWalker},
Flow,
};
@@ -72,9 +74,9 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
/// This should only be called once per [`RequestHint`].
fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
&'this mut self,
- visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>,
+ visitor: DynVisitorWith<'visitor, 'ctx, Protocol>,
hint: MetaHint<'hint, 'ctx, Protocol>,
- ) -> ErasedEffective<'e, Flow, Protocol::Effect>
+ ) -> ErasedEffective<'e, VisitResult, Protocol::Effect>
where
'ctx: 'this + 'visitor + 'hint + 'e;
@@ -85,6 +87,47 @@ pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
) -> ErasedEffective<'a, Result<MetaKnown<'a, 'ctx, Protocol>, ()>, Protocol::Effect>;
}
+pub struct DynVisitorWith<'temp, 'ctx, Protocol: ?Sized> {
+ visitor: DynVisitor<'temp, 'ctx>,
+ _marker: Marker<Protocol>,
+}
+
+pub trait HasProtocol<Protocol: ?Sized> {}
+
+impl<'temp, 'ctx: 'temp, Protocol: ?Sized + HintMeta> DynVisitorWith<'temp, 'ctx, Protocol> {
+ pub fn new<T>(visitor: &'temp mut T) -> Self
+ where
+ T: AnyTrait<'ctx> + HasProtocol<Protocol> + Ss,
+ {
+ Self {
+ visitor: DynVisitor(visitor),
+ _marker: Default::default(),
+ }
+ }
+
+ pub fn as_known(&mut self) -> &mut TypeName::T<'_, 'ctx, Protocol> {
+ self.visitor.upcast_mut::<Protocol>().unwrap()
+ }
+
+ pub fn into_inner(self) -> DynVisitor<'temp, 'ctx> {
+ self.visitor
+ }
+}
+
+impl<'temp, 'ctx, Protocol: ?Sized> Deref for DynVisitorWith<'temp, 'ctx, Protocol> {
+ type Target = DynVisitor<'temp, 'ctx>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.visitor
+ }
+}
+
+impl<'temp, 'ctx, Protocol: ?Sized> DerefMut for DynVisitorWith<'temp, 'ctx, Protocol> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ &mut self.visitor
+ }
+}
+
pub struct HintProto<Protocol: ?Sized>(Marker<Protocol>);
impl<'a, 'ctx, Protocol: ?Sized> TypeName::MemberTypeForLt<'a, 'ctx, &'a &'ctx ()>
@@ -110,13 +153,19 @@ pub fn hint_protocol<
'hint: 'e,
'e,
Protocol: ?Sized + HintMeta,
+ T,
>(
walker: DynWalker<'walker, 'ctx>,
- visitor: &'visitor mut TypeName::T<'visitor, 'ctx, Protocol>,
+ visitor: &'visitor mut T,
hint: MetaHint<'hint, 'ctx, Protocol>,
-) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect> {
+) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect>
+where
+ T: AnyTrait<'ctx> + HasProtocol<Protocol> + Ss,
+{
if let Some(object) = walker.0.upcast_mut::<HintProto<Protocol>>() {
- object.hint(visitor, hint).map(Into::into)
+ object
+ .hint(DynVisitorWith::new(visitor), hint)
+ .map(Into::into)
} else {
VisitResult::Skipped(()).ready()
}