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

use crate::{
    protocol::{AsObj as _, Effect, EffectAnyTrait, SyncEffect, Visitor, Yield},
    Walker,
};

/// A buildable type.
pub trait Build<'ctx, E: EffectAnyTrait<'ctx>>: Sized {
    /// The builder that can be used to build a value of `Self`.
    type Builder: Builder<'ctx, E, Value = Self>;
}

/// Builder for a type.
///
/// The `'ctx` lifetime is some lifetime that is longer than the walker.
/// As such, the built value can borrow from other data with a `'ctx` lifetimes.
///
/// A builder allows creating a value of a type [`Self::Value`].
/// The way to use a builder is as follows.
/// - Call [`Default::default()`] to create an instance of the builder.
/// - Call [`Self::as_visitor()`] and give it to a walker's
///     [`walk()`][crate::walk::Walker::walk]. The walker will then fill
///     the builder with data from it's walk.
/// - Call [`Self::build()`] to finish building the value and get any errors
///     that happened during filling it with data.
pub trait Builder<'ctx, E: EffectAnyTrait<'ctx>>: AsVisitor<'ctx, E> {
    type Effect: Effect<'ctx, Result<Self::Value, Self::Error>>;

    type Seed;

    /// Error that can happen during filling the builder with data.
    type Error;

    /// Type to be built.
    type Value;

    fn from_seed(seed: Self::Seed) -> Self;

    /// Finish the value.
    ///
    /// If an error happened with the builder during the walk
    /// it will be reported here.
    fn build<'a>(self) -> Yield<'a, 'ctx, Result<Self::Value, Self::Error>, Self::Effect> where Self: 'a;
}

pub trait AsVisitor<'ctx, E: EffectAnyTrait<'ctx>> {
    /// Get the builder as a visitor that a walker can use.
    ///
    /// This is expected to just be `self`.
    fn as_visitor(&mut self) -> Visitor<'_, 'ctx, E>;
}

pub trait DefaultBuilder<'ctx, E: EffectAnyTrait<'ctx>>: Builder<'ctx, E> {
    fn default() -> Self;
}

impl<'ctx, B: Builder<'ctx, E>, E: EffectAnyTrait<'ctx>> DefaultBuilder<'ctx, E> for B
where
    B::Seed: Default,
{
    fn default() -> Self {
        Self::from_seed(Default::default())
    }
}

#[derive(Debug)]
pub enum BuildError<B, W> {
    Builder(B),
    Walker(W),
}

#[inline]
pub fn build<'ctx, T: Build<'ctx, SyncEffect>, W: Walker<'ctx, Effect = SyncEffect>>(
    walker: W,
) -> Result<
    T,
    BuildError<
        <<T as Build<'ctx, SyncEffect>>::Builder as Builder<'ctx, SyncEffect>>::Error,
        W::Error,
    >,
>
where
    <T as Build<'ctx, SyncEffect>>::Builder: Builder<'ctx, SyncEffect, Effect = SyncEffect>,
    <<T as Build<'ctx, SyncEffect>>::Builder as Builder<'ctx, SyncEffect>>::Seed: Default,
{
    let mut builder = T::Builder::from_seed(Default::default());

    if let Err(err) = walker.walk(builder.as_visitor().as_obj_mut()) {
        return Err(BuildError::Walker(err));
    }

    builder.build().map_err(BuildError::Builder)
}

pub fn build_with<'ctx, B: Builder<'ctx, SyncEffect, Effect = SyncEffect>, W: Walker<'ctx, Effect = SyncEffect>>(
    walker: W,
) -> Result<B::Value, BuildError<B::Error, W::Error>>
where
    <B as Builder<'ctx, SyncEffect>>::Seed: Default,
{
    let mut builder = B::from_seed(Default::default());

    if let Err(err) = walker.walk(builder.as_visitor().as_obj_mut()) {
        return Err(BuildError::Walker(err));
    }

    builder.build().map_err(BuildError::Builder)
}

// #[cfg(feature = "alloc")]
// use crate::protocol::AsyncEffect;
//
// #[cfg(feature = "alloc")]
// pub async fn async_build_with<
//     'ctx,
//     B: DefaultBuilder<'ctx, AsyncEffect>,
//     W: for<'a> Walker<'a, 'ctx, Effect = AsyncEffect>,
// >(
//     walker: W,
// ) -> Result<B::Value, BuildError<B::Error, W::Error>> {
//     let mut builder = B::default();
//
//     if let core::ops::ControlFlow::Break(err) = walker.walk(builder.as_visitor()).await {
//         return Err(BuildError::Walker(err));
//     }
//
//     builder.build().map_err(BuildError::Builder)
// }