error_accumulator/
builder.rs

1//! Builder to parse input and accumulate errors.
2
3use std::marker::PhantomData;
4
5use crate::{AccumulatedError, Constructor, cons::ToTuple};
6
7mod array;
8mod field;
9mod strukt;
10
11pub use self::{array::ArrayBuilder, field::FieldBuilder, strukt::StructBuilder};
12
13/// Parent builders can have child builders to simulate nested structures.
14pub trait ErrorBuilderParent<T> {
15    /// The parent builder after the child builder finished.
16    ///
17    /// Due to the strongly typed nature of most builders it is common that
18    /// after the final result of the child builder is recorded the parent is
19    /// turned into another type.
20    type AfterRecord;
21
22    /// Record the final result of the child builder.
23    fn finish_child_builder(self, child_result: Result<T, AccumulatedError>) -> Self::AfterRecord;
24}
25
26/// Intermediate state when either [`FieldBuilder::on_ok()`] or
27/// [`StructBuilder::on_ok()`] were called.
28///
29/// See those method's documentations for more details.
30#[derive(Debug)]
31pub struct BuilderFinisher<Parent, Out, List, Constructor> {
32    parent: Parent,
33    accumulated_errors: AccumulatedError,
34    values: List,
35    constructor: Constructor,
36    _marker: PhantomData<Out>,
37}
38
39impl<Parent, Value, List, C> BuilderFinisher<Parent, Value, List, C>
40where
41    Parent: ErrorBuilderParent<Value>,
42    List: ToTuple,
43    C: Constructor<List::List, Value>,
44{
45    /// Finish the wrapped builder and pass the final result to the parent
46    /// builder.
47    pub fn finish(self) -> Parent::AfterRecord {
48        let result = if self.accumulated_errors.is_empty() {
49            Ok(self.constructor.construct(self.values.unwrap_tuple()))
50        } else {
51            Err(self.accumulated_errors)
52        };
53
54        self.parent.finish_child_builder(result)
55    }
56}