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
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "alloc")]
extern crate alloc;

pub mod build;
pub mod error;
pub mod impls;
pub mod protocol;
pub mod protocols;
pub mod transform;
pub mod walk;

// use buildable::Buildable;
use error::{UniError, WalkerError};
use protocol::{AnyHint, AnyVisit, Hint, ProtocolDescription, ProtocolId, Visit};

// pub use buildable::Buildable;
// pub use walkable::{Walkable, WalkableMut, WalkableRef};

/// Token value showing a hint was given.
///
/// This is used by [`Visitor::request_hint`] to tell the walker if a hint
/// was given or not. A `Some(HintGiven)` means the visitor gave a hint by
/// calling a [`Hint::hint`] method. A `None` means the visitor did not
/// give a hint to the walker for what protocol to use.
///
/// [`Hint::hint`] methods return an instance of this type so [`Visitor::request_hint`]
/// can just return that instance.
#[must_use]
#[derive(Debug)]
pub struct HintGiven;

/// Status of a walker after walking using a visitor.
///
/// Some walkers can be walked multiple times to extract multiple
/// values.
pub enum WalkStatus {
    /// The walker is done.
    ///
    /// Attemping to call `walk` is likely to result in an error.
    Done,

    /// The walker can continue.
    Continue,
}

/// Walker over a value with lifetime `'value`.
pub trait Walker<'value, 'ctx: 'value, VisitorErr> {
    /// Error type the walker generates.
    type Error;

    /// Walk the walker over the value.
    ///
    /// This is the main entrypoint for walking a value.
    /// The walker should call [`Visit::visit`] on the provided visitor as it walks.
    ///
    /// The default impl calls [`Visitor::request_hint`] then returns an error if no hint
    /// was given. Self describing formats can replace the default impl to fall back to
    /// their own logic if no hint is given. It is recommended to keep the call to
    /// [`Visitor::request_hint`] before using walker specific logic to pick a protocol.
    fn walk(
        &mut self,
        visitor: &mut dyn Visitor<'value, 'ctx, Self::Error, Error = VisitorErr>,
    ) -> Result<WalkStatus, UniError<Self::Error, VisitorErr>>;

    fn all_protocols() -> impl Iterator<Item = ProtocolDescription>
    where
        Self: Sized;
}

pub fn walk_with_hints<'value, 'ctx: 'value, VisitorErr, H: WalkerHints<'value, 'ctx, VisitorErr>>(
    hints: &mut H,
    visitor: &mut dyn Visitor<'value, 'ctx, H::Error, Error = VisitorErr>,
) -> Result<WalkStatus, UniError<H::Error, VisitorErr>>
where
    H::Error: WalkerError<'value, 'ctx>,
{
    // Request that the visitor give us a hint of what protocol to use.
    match visitor.request_hint(hints, true)? {
        Some(HintGiven) => Ok(WalkStatus::Done),
        None => Err(UniError::Walker(
            <H::Error as WalkerError<'value, 'ctx>>::needs_hint(),
        )),
    }
}

/// Hint lookup for a walker.
pub trait WalkerHints<'value, 'ctx: 'value, VisitorErr> {
    type Error;

    /// Query the walker for a given protocol.
    ///
    /// If the walker doesn't support the protocol then a `None` is returned.
    /// Note, a walker can return `None` if it can't handle a hint of the protocol for the given
    /// value.
    fn protocol(
        &mut self,
        id: ProtocolId,
    ) -> Option<AnyHint<'_, 'value, 'ctx, Self::Error, VisitorErr>>;
}

/// Visitor over a value to be built.
pub trait Visitor<'value, 'ctx: 'value, WalkerErr> {
    type Error;

    /// Request the visitor hint what protocol to use.
    ///
    /// It is not recommended to call this while in a protocol hint as a walker.
    /// Calling this method when already processing a hint can cause a infinite loop.
    ///
    /// The visitor will hint the protocol by calling the [`Hint::hint`] method on the
    /// the walker's returned hint instance for the protocol.
    ///
    /// A return value of `Ok(None)` means no hint was given to the walker.
    fn request_hint(
        &mut self,
        hints: &mut dyn WalkerHints<'value, 'ctx, Self::Error, Error = WalkerErr>,
        need_hint: bool,
    ) -> Result<Option<HintGiven>, UniError<WalkerErr, Self::Error>> {
        let _ = hints;
        let _ = need_hint;
        Ok(None)
    }

    /// Query the visitor for a given protocol.
    ///
    /// If the visitor doesn't support the protocol then a `None` is returned.
    fn protocol(
        &mut self,
        id: ProtocolId,
    ) -> Option<AnyVisit<'_, 'value, 'ctx, WalkerErr, Self::Error>>;

    fn all_protocols() -> impl Iterator<Item = ProtocolDescription>
    where
        Self: Sized;
}