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
//! 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::DynVisitor,
    Flow,
};

higher_ranked_trait! {
    pub type class Meta for<'a, 'ctx> {
        type Bound = &'a &'ctx ();

        type T: { Send + Sized } where { 'ctx: 'a };

        type HigherRanked: { };
    }
}

higher_ranked_type! {
    impl Meta {
        impl['a, 'ctx] type T['a, 'ctx] for () = ();
        impl['a, 'ctx] type HigherRanked['a, 'ctx] for () = ();
    }
}

/// 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: 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<'a>(
        &'a mut self,
        visitor: DynVisitor<'a, 'ctx>,
        hint: MetaHint<'a, 'ctx, Protocol>,
    ) -> Future<'a, Flow, Protocol::Effect>;

    /// Ask the walker for information about it's support of the protocol.
    fn known<'a>(
        &'a mut self,
        hint: &'a MetaHint<'a, 'ctx, Protocol>,
    ) -> Future<'a, Result<MetaKnown<'a, 'ctx, Protocol>, ()>, Protocol::Effect>;
}

pub struct HintProto<Protocol: ?Sized>(Marker<Protocol>);

higher_ranked_type! {
    impl TypeName {
        impl['a, 'ctx, Protocol] type T['a, 'ctx] for HintProto<Protocol> =
            dyn Hint<'ctx, Protocol> + Send + Sync + 'a
        where {
            Protocol: 'static,
        };

        impl['a, 'ctx, Protocol] type HigherRanked['a, 'ctx] for dyn Hint<'ctx, Protocol> + Send + Sync + 'a =
            HintProto<Protocol>
        where {
            Protocol: 'static,
        };
    }
}