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
//! 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);
//     }
// }