error_accumulator/builder/
field.rs1use std::{error::Error, marker::PhantomData};
2
3use crate::{
4 append_or_record,
5 builder::{BuilderFinisher, ErrorBuilderParent},
6 cons::{Append, AsRefTuple, Cons, Nil, ToTuple},
7 construct::{Constructor, ListValidator},
8 error::AccumulatedError,
9 path::SourcePath,
10};
11
12#[derive(Debug)]
14pub struct FieldBuilder<Parent, Value, List> {
15 parent: Parent,
16 errors: AccumulatedError,
17 field: SourcePath,
18 values: List,
19 _marker: PhantomData<Value>,
20}
21
22impl<Parent, Value> FieldBuilder<Parent, Value, Nil>
23where
24 Parent: ErrorBuilderParent<Value>,
25{
26 pub(crate) fn new(parent: Parent, path: SourcePath) -> Self {
27 Self {
28 field: path,
29 parent,
30 errors: Default::default(),
31 values: Nil,
32 _marker: PhantomData,
33 }
34 }
35}
36
37impl<Parent, Value, List> FieldBuilder<Parent, Value, List>
38where
39 Parent: ErrorBuilderParent<Value>,
40{
41 pub fn value<T, E>(self, result: Result<T, E>) -> FieldBuilder<Parent, Value, List::Output>
43 where
44 List: Append<T>,
45 E: Error + Send + Sync + 'static,
46 {
47 let Self {
48 parent,
49 mut errors,
50 field,
51 values,
52 _marker,
53 } = self;
54
55 let values = append_or_record(values, &field, result, &mut errors);
56
57 FieldBuilder {
58 parent,
59 errors,
60 field,
61 values,
62 _marker,
63 }
64 }
65
66 pub fn value_ok<T>(self, value: T) -> FieldBuilder<Parent, Value, List::Output>
71 where
72 List: Append<T>,
73 {
74 let Self {
75 parent,
76 errors,
77 field,
78 values,
79 _marker,
80 } = self;
81
82 let values = values.append(value);
83
84 FieldBuilder {
85 parent,
86 errors,
87 field,
88 values,
89 _marker,
90 }
91 }
92
93 pub fn with_previous<Valid, T, E>(
101 self,
102 validator: Valid,
103 ) -> FieldBuilder<Parent, Value, List::Output>
104 where
105 Valid: ListValidator<List, T, E>,
106 List: AsRefTuple + Append<T>,
107 E: Error + Send + Sync + 'static,
108 {
109 let Self {
110 parent,
111 mut errors,
112 field,
113 values,
114 _marker,
115 } = self;
116
117 let values = if errors.is_empty() {
118 let result = validator.validate(&values);
119 append_or_record(values, &field, result, &mut errors)
120 } else {
121 values.append(None)
122 };
123
124 FieldBuilder {
125 parent,
126 errors,
127 field,
128 values,
129 _marker,
130 }
131 }
132
133 pub fn on_ok<C>(self, constructor: C) -> BuilderFinisher<Parent, Value, List, C>
136 where
137 List: ToTuple,
138 C: Constructor<List::List, Value>,
139 {
140 BuilderFinisher {
141 parent: self.parent,
142 accumulated_errors: self.errors,
143 values: self.values,
144 constructor,
145 _marker: PhantomData,
146 }
147 }
148}
149
150impl<Parent, Value> FieldBuilder<Parent, Value, Cons<Value, Nil>>
151where
152 Parent: ErrorBuilderParent<Value>,
153{
154 pub fn finish(self) -> Parent::AfterRecord {
157 let result = if self.errors.is_empty() {
158 let (value,) = self.values.unwrap_tuple();
159 Ok(value)
160 } else {
161 Err(self.errors)
162 };
163
164 self.parent.finish_child_builder(result)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use std::num::NonZeroI16;
171
172 use crate::{ErrorAccumulator, test_util::n};
173
174 #[test]
175 fn should_allow_multivalue_field_record() {
176 let (num,) = ErrorAccumulator::new()
177 .field_builder(n("foo"))
178 .value("42".parse::<u32>())
179 .value(NonZeroI16::try_from(-5))
180 .on_ok(|v, _| v)
181 .finish()
182 .analyse()
183 .unwrap();
184
185 assert_eq!(num, 42);
186 }
187
188 #[test]
189 fn should_return_error_on_multivalue_field_record() {
190 let err = ErrorAccumulator::new()
191 .field_builder(n("bar"))
192 .value("42".parse::<u32>())
193 .value(NonZeroI16::try_from(0))
194 .on_ok(|v, _| v)
195 .finish()
196 .analyse()
197 .unwrap_err();
198
199 assert_eq!(err.len(), 1);
200 }
201}