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
//! 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::{
    nameable,
    protocol::{ControlFlow, Visitor},
};

/// 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 irreversable way.
    type Known<'a>
    where
        'ctx: 'a;

    /// 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: HintMeta<'ctx>> {
    /// Hint to the walker to use the `P` protocol.
    ///
    /// This should only be called once per [`RequestHint`].
    fn hint(&mut self, visitor: Visitor<'_, 'ctx>, hint: Protocol::Hint) -> ControlFlow;

    /// Ask the walker for information about it's support of the protocol.
    fn known(&mut self, hint: &Protocol::Hint) -> ControlFlow<(), Protocol::Known<'_>>;
}

nameable! {
    pub ['a, 'ctx, Protocol]
    dyn Hint<'ctx, Protocol> + 'a where {'ctx: 'a, Protocol: ?Sized}
    dyn Hint<'ctx, Protocol::Nameable> + 'a where {'ctx: 'a, Protocol: ?Sized}
}

#[cfg(test)]
mod test {
    use crate::any::{LtTypeId, TypeNameable};

    use super::*;

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

        nameable! {
            ['a, 'ctx]
            Y where {}
        }

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

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

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

            type Hint = ();
        }

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