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
//! 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, TypeNameable},
    nameable,
    protocol::{ControlFlowFor, Effect, SyncEffect, Visitor},
};

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

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

/// Object implementing the [`Hint`] protocol.
pub trait Hint<'ctx, Protocol: ?Sized + for<'a> HintMeta<'a, 'ctx>, E = SyncEffect> 
where
    E: Effect<'ctx> + Effect<'ctx, <Protocol as HintMeta<'a, 'ctx>>::Known>
{
    /// Hint to the walker to use the `P` protocol.
    ///
    /// This should only be called once per [`RequestHint`].
    fn hint<'a>(
        &'a mut self,
        visitor: &'a mut Visitor<'a, 'ctx, E>,
        hint: <Protocol as HintMeta<'a, 'ctx>>::Hint,
    ) -> ControlFlowFor<'a, 'ctx, E>;

    /// Ask the walker for information about it's support of the protocol.
    fn known<'a>(
        &'a mut self,
        hint: &'a <Protocol as HintMeta<'a, 'ctx>>::Hint,
    ) -> ControlFlowFor<'a, 'ctx, E, <Protocol as HintMeta<'a, 'ctx>>::Known>
    where
        'ctx: 'a;
}

nameable! {
    pub struct Name['a, 'ctx, Protocol, E];

    impl [Protocol::Name, E] for dyn Hint<'ctx, Protocol, E> + 'a where {
        Protocol: TypeNameable<'a, 'ctx> + ?Sized,
        E: Effect<'ctx>,
        'ctx: 'a,
    }

    impl [Protocol, E] where dyn Hint<'ctx, Protocol::Nameable, E> + 'a {
        Protocol: TypeName<'a, 'ctx> + ?Sized,
        E: Effect<'ctx>,
        'ctx: 'a,
    }
}

#[cfg(test)]
mod test {
    use core::ops::ControlFlow;

    use crate::any::{LtTypeId, TypeNameable};

    use super::*;

    #[test]
    fn demo() {
        struct X;
        struct Y;

        nameable! {
            struct Name['a, 'ctx];
            impl for Y where {}
        }

        impl<'ctx, X> Hint<'ctx, Y> for X {
            fn hint<'a>(
                &'a mut self,
                visitor: &'a mut Visitor<'a, 'ctx>,
                hint: <Y as HintMeta<'ctx>>::Hint<'a>,
            ) -> ControlFlow<()> {
                todo!()
            }

            fn known<'a>(
                &'a mut self,
                hint: &'a <Y as HintMeta<'ctx>>::Hint<'a>,
            ) -> ControlFlow<(), <Y as HintMeta<'ctx>>::Known<'a>>
            where
                'ctx: 'a,
            {
                todo!()
            }
        }

        impl<'ctx> HintMeta<'ctx> for Y {
            type Known<'a> = () where 'ctx: 'a;

            type Hint<'a> = () where 'ctx: 'a;
        }

        let x = X;
        let y: &dyn Hint<'_, Y> = &x;

        fn id<'a, 'ctx, T: ?Sized + TypeNameable<'a, 'ctx>>(x: &T) {
            dbg!(LtTypeId::of::<T>());
        }

        id(y);

        // todo!();
    }
}