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
pub mod walkers;

use core::ops::ControlFlow;

use crate::{
    effect::{Effect, Future},
    protocol::Visitor,
};

/// A type that can be walked.
pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized {
    /// The walker for the type.
    type Walker<E: Effect<'ctx>>: Walker<
        'ctx,
        Error = Self::Error,
        Output = Self::Output,
        Effect = E,
    >;

    fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>;
}

pub trait WalkerTypes<'ctx> {
    type Error: Send;

    /// An arbitrary type the walker is left with after walking.
    ///
    /// Its recommended that this is `Self` if the walker is repeatable.
    type Output: Send;
}

/// Walker for a type.
///
/// The `'ctx` lifetime is some lifetime that is longer than `Self`.
/// Data from the value may borrow using `'ctx`.
///
/// The way to use a walker is as follows.
/// - Call [From::from()] with a value to be walked to make a walker.
/// - Call [Self::walk()] to walk the value. Data will be sent to the provided
///     visitor.
pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send {
    type Effect: Effect<'ctx>;

    /// Walk the value.
    ///
    /// The walker should send data to the `visitor` as it walks the value.
    fn walk<'a>(
        self,
        visitor: Visitor<'a, 'ctx>,
    ) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect>
    where
        Self: 'a;
}

pub trait DynWalker<'ctx>: Send {
    type Effect: Effect<'ctx>;

    fn walk<'a>(
        &'a mut self,
        visitor: Visitor<'a, 'ctx>,
    ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
    where
        Self: 'a;
}

enum DynWalkerState<'ctx, W: WalkerTypes<'ctx>> {
    Walking,
    Pending(W),
    Done(Result<W::Output, W::Error>),
}

pub enum DynWalkerError<'ctx, W: WalkerTypes<'ctx>> {
    NeverWalked(W),

    /// This can only happen if a panic happens furing the walk and is then caught before calling
    /// finish..
    WalkNeverFinished,

    Walker(W::Error),
}

pub struct DynWalkerAdapter<'ctx, W: WalkerTypes<'ctx>> {
    state: DynWalkerState<'ctx, W>,
}

impl<'ctx, W: WalkerTypes<'ctx>> DynWalkerAdapter<'ctx, W> {
    pub fn new(walker: W) -> Self {
        Self {
            state: DynWalkerState::Pending(walker),
        }
    }

    pub fn finish(self) -> Result<W::Output, DynWalkerError<'ctx, W>> {
        match self.state {
            DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished),
            DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)),
            DynWalkerState::Done(result) => result.map_err(DynWalkerError::Walker),
        }
    }
}

impl<'ctx, W: Walker<'ctx>> DynWalker<'ctx> for DynWalkerAdapter<'ctx, W> {
    type Effect = W::Effect;

    fn walk<'a>(
        &'a mut self,
        visitor: Visitor<'a, 'ctx>,
    ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect>
    where
        Self: 'a,
    {
        Self::Effect::wrap(async {
            if let DynWalkerState::Pending(walker) =
                core::mem::replace(&mut self.state, DynWalkerState::Walking)
            {
                // Walk the walker.
                self.state = DynWalkerState::Done(walker.walk(visitor).await);
            } else {
                // Can't do anything if the walker has already been walked.
            }
            ControlFlow::Continue(())
        })
    }
}