1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
//! 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::{Deref, DerefMut};

use crate::{
    any::{AnyTrait, TypeName},
    effect::{Effect, EffectiveExt as _, ErasedEffective, ReadyExt as _, Ss},
    hkt::Marker,
    protocol::{visitor::VisitResult, DynVisitor, DynWalker},
    Flow,
};

#[allow(non_snake_case)]
pub mod Meta {
    pub trait MemberTypeForLt<'a, 'ctx: 'a, B> {
        type T: ?Sized + LowerTypeWithBound<'a, 'ctx, &'a &'ctx (), Higher = Self>;
    }

    pub trait MemberType: for<'a, 'ctx> MemberTypeForLt<'a, 'ctx, &'a &'ctx ()> {}

    impl<T: ?Sized> MemberType for T where T: for<'a, 'ctx> MemberTypeForLt<'a, 'ctx, &'a &'ctx ()> {}

    pub trait LowerTypeWithBound<'a, 'ctx: 'a, B>: 'a + Send + Sync + Sized {
        type Higher: ?Sized + MemberTypeForLt<'a, 'ctx, &'a &'ctx (), T = Self> + MemberType;
    }

    pub trait LowerType<'a, 'ctx: 'a>: LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()> {}

    impl<'a, 'ctx: 'a, T: ?Sized> LowerType<'a, 'ctx> for T where
        T: LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()>
    {
    }

    pub type T<'a, 'ctx, __> = <__ as MemberTypeForLt<'a, 'ctx, &'a &'ctx ()>>::T;
    pub type HigherRanked<'a, 'ctx, __> =
        <__ as LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()>>::Higher;
}

impl<'a, 'ctx> Meta::MemberTypeForLt<'a, 'ctx, &'a &'ctx ()> for () {
    type T = ();
}

impl<'a, 'ctx: 'a> Meta::LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()> for () {
    type Higher = ();
}

/// Meta information for the hint.
///
/// This gives the visitor more information to work from when selecting a hint.
pub trait HintMeta: TypeName::MemberType + 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: Meta::MemberType;

    /// Extra information the visitor can give to the walker about what it is expecting.
    type Hint: Meta::MemberType;

    type Effect: Effect;
}

pub type MetaKnown<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Known>;
pub type MetaHint<'a, 'ctx, Protocol> = Meta::T<'a, 'ctx, <Protocol as HintMeta>::Hint>;

/// Object implementing the [`Hint`] protocol.
pub trait Hint<'ctx, Protocol: ?Sized + HintMeta> {
    /// Hint to the walker to use the `P` protocol.
    ///
    /// This should only be called once per [`RequestHint`].
    fn hint<'this: 'e, 'visitor: 'e, 'hint: 'e, 'e>(
        &'this mut self,
        visitor: DynVisitorWith<'visitor, 'ctx, Protocol>,
        hint: MetaHint<'hint, 'ctx, Protocol>,
    ) -> ErasedEffective<'e, VisitResult, Protocol::Effect>
    where
        'ctx: 'this + 'visitor + 'hint + 'e;

    /// Ask the walker for information about it's support of the protocol.
    fn known<'a>(
        &'a mut self,
        hint: &'a MetaHint<'a, 'ctx, Protocol>,
    ) -> 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 ()>
    for HintProto<Protocol>
where
    Protocol: HintMeta,
{
    type T = dyn Hint<'ctx, Protocol> + Send + Sync + 'a;
}

impl<'a, 'ctx, Protocol: ?Sized> TypeName::LowerTypeWithBound<'a, 'ctx, &'a &'ctx ()>
    for dyn Hint<'ctx, Protocol> + Send + Sync + 'a
where
    Protocol: HintMeta,
{
    type Higher = HintProto<Protocol>;
}

pub fn hint_protocol<
    'ctx,
    'walker: 'e,
    'visitor: 'e,
    'hint: 'e,
    'e,
    Protocol: ?Sized + HintMeta,
    T,
>(
    walker: DynWalker<'walker, 'ctx>,
    visitor: &'visitor mut T,
    hint: MetaHint<'hint, 'ctx, Protocol>,
) -> ErasedEffective<'e, VisitResult<()>, Protocol::Effect>
where
    T: AnyTrait<'ctx> + HasProtocol<Protocol> + Ss,
{
    if let Some(object) = walker.0.upcast_mut::<HintProto<Protocol>>() {
        object
            .hint(DynVisitorWith::new(visitor), hint)
            .map(Into::into)
    } else {
        VisitResult::Skipped(()).ready()
    }
}