Skip to content

Commit 6cc77e6

Browse files
committed
reduce code duplication
1 parent ae1f844 commit 6cc77e6

File tree

4 files changed

+88
-99
lines changed

4 files changed

+88
-99
lines changed

src/input/iterator.rs

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
1-
use pyo3::{PyErr, Python};
1+
use pyo3::{PyErr, PyObject, PyResult, Python};
22

33
use super::Input;
44

5-
use crate::errors::{py_err_string, ErrorType, LocItem, ValError, ValLineError, ValResult};
5+
use crate::validators::Validator;
6+
use crate::{
7+
definitions::Definitions,
8+
errors::{py_err_string, ErrorType, LocItem, ValError, ValLineError, ValResult},
9+
recursion_guard::RecursionGuard,
10+
validators::CombinedValidator,
11+
validators::Extra,
12+
};
613

714
pub fn calculate_output_init_capacity(iterator_size: Option<usize>, max_length: Option<usize>) -> usize {
815
// The smaller number of either the input size or the max output length
@@ -126,6 +133,7 @@ impl<'data> IterableValidationChecks<'data> {
126133
}
127134
}
128135

136+
#[inline(always)]
129137
pub fn map_iter_error<'data>(
130138
py: Python<'data>,
131139
input: &'data impl Input<'data>,
@@ -140,3 +148,37 @@ pub fn map_iter_error<'data>(
140148
loc.into(),
141149
)
142150
}
151+
152+
#[allow(clippy::too_many_arguments)]
153+
#[inline(always)]
154+
pub fn validate_iterator<'s, 'data, V, O, W, L>(
155+
py: Python<'data>,
156+
input: &'data impl Input<'data>,
157+
extra: &'s Extra<'s>,
158+
definitions: &'data Definitions<CombinedValidator>,
159+
recursion_guard: &'s mut RecursionGuard,
160+
checks: &mut IterableValidationChecks<'data>,
161+
iter: impl Iterator<Item = PyResult<&'data V>>,
162+
items_validator: &'s CombinedValidator,
163+
output: &mut O,
164+
write: &mut W,
165+
len: &L,
166+
) -> ValResult<'data, ()>
167+
where
168+
V: Input<'data> + 'data,
169+
W: FnMut(&mut O, PyObject) -> PyResult<()>,
170+
L: Fn(&O) -> usize,
171+
{
172+
for (index, result) in iter.enumerate() {
173+
let value = result.map_err(|e| map_iter_error(py, input, index, e))?;
174+
let result = items_validator
175+
.validate(py, value, extra, definitions, recursion_guard)
176+
.map_err(|e| e.with_outer_location(index.into()));
177+
if let Some(value) = checks.filter_validation_result(result, input)? {
178+
write(output, value)?;
179+
checks.check_output_length(len(output), input)?;
180+
}
181+
}
182+
checks.finish(input)?;
183+
Ok(())
184+
}

src/validators/list.rs

Lines changed: 15 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use pyo3::types::PyDict;
33

44
use crate::build_tools::SchemaDict;
55
use crate::errors::{ErrorType, ValError, ValResult};
6-
use crate::input::iterator::{calculate_output_init_capacity, map_iter_error, IterableValidationChecks};
6+
use crate::input::iterator::{calculate_output_init_capacity, validate_iterator, IterableValidationChecks};
77
use crate::input::Input;
88
use crate::input::{iterator::LengthConstraints, GenericIterable};
99
use crate::recursion_guard::RecursionGuard;
@@ -90,7 +90,14 @@ impl Validator for ListValidator {
9090

9191
let mut checks = IterableValidationChecks::new(false, length_constraints, FIELD_TYPE);
9292

93-
let mut output = Vec::with_capacity(calculate_output_init_capacity(generic_iterable.len(), self.max_length));
93+
let mut output: Vec<PyObject> =
94+
Vec::with_capacity(calculate_output_init_capacity(generic_iterable.len(), self.max_length));
95+
96+
let len = |output: &Vec<PyObject>| output.len();
97+
let mut write = |output: &mut Vec<PyObject>, ob: PyObject| {
98+
output.push(ob);
99+
Ok(())
100+
};
94101

95102
match (generic_iterable, strict) {
96103
// Always allow actual lists or JSON arrays
@@ -104,6 +111,8 @@ impl Validator for ListValidator {
104111
iter.iter().map(Ok),
105112
&self.item_validator,
106113
&mut output,
114+
&mut write,
115+
&len,
107116
)?,
108117
(GenericIterable::List(iter), _) => validate_iterator(
109118
py,
@@ -115,6 +124,8 @@ impl Validator for ListValidator {
115124
iter.iter().map(Ok),
116125
&self.item_validator,
117126
&mut output,
127+
&mut write,
128+
&len,
118129
)?,
119130
// If not in strict mode we also accept any iterable except str, bytes or mappings
120131
// This may seem counterintuitive since a Mapping is a less generic type than an arbitrary
@@ -138,6 +149,8 @@ impl Validator for ListValidator {
138149
iter,
139150
&self.item_validator,
140151
&mut output,
152+
&mut write,
153+
&len,
141154
)?,
142155
Err(_) => return Err(ValError::new(ErrorType::ListType, input)),
143156
},
@@ -169,32 +182,3 @@ impl Validator for ListValidator {
169182
Ok(())
170183
}
171184
}
172-
173-
#[allow(clippy::too_many_arguments)]
174-
fn validate_iterator<'s, 'data, V>(
175-
py: Python<'data>,
176-
input: &'data impl Input<'data>,
177-
extra: &'s Extra<'s>,
178-
definitions: &'data Definitions<CombinedValidator>,
179-
recursion_guard: &'s mut RecursionGuard,
180-
checks: &mut IterableValidationChecks<'data>,
181-
iter: impl Iterator<Item = PyResult<&'data V>>,
182-
items_validator: &'s CombinedValidator,
183-
output: &mut Vec<PyObject>,
184-
) -> ValResult<'data, ()>
185-
where
186-
V: Input<'data> + 'data,
187-
{
188-
for (index, result) in iter.enumerate() {
189-
let value = result.map_err(|e| map_iter_error(py, input, index, e))?;
190-
let result = items_validator
191-
.validate(py, value, extra, definitions, recursion_guard)
192-
.map_err(|e| e.with_outer_location(index.into()));
193-
if let Some(value) = checks.filter_validation_result(result, input)? {
194-
output.push(value);
195-
checks.check_output_length(output.len(), input)?;
196-
}
197-
}
198-
checks.finish(input)?;
199-
Ok(())
200-
}

src/validators/sets.rs

Lines changed: 17 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use pyo3::types::{PyDict, PyFrozenSet, PySet};
33

44
use crate::build_tools::SchemaDict;
55
use crate::errors::{ErrorType, ValResult};
6-
use crate::input::iterator::{map_iter_error, IterableValidationChecks, LengthConstraints};
6+
use crate::input::iterator::{validate_iterator, IterableValidationChecks, LengthConstraints};
77
use crate::input::{GenericIterable, Input};
88
use crate::recursion_guard::RecursionGuard;
99

@@ -92,7 +92,10 @@ impl IntoSetValidator {
9292

9393
let mut checks = IterableValidationChecks::new(false, length_constraints, field_type);
9494

95-
let output = PySet::empty(py)?;
95+
let mut output = PySet::empty(py)?;
96+
97+
let len = |output: &&'data PySet| output.len();
98+
let mut write = |output: &mut &'data PySet, ob: PyObject| output.add(ob);
9699

97100
match (generic_iterable, strict, set_type) {
98101
// Always allow actual lists or JSON arrays
@@ -105,7 +108,9 @@ impl IntoSetValidator {
105108
&mut checks,
106109
iter.iter().map(Ok),
107110
&self.item_validator,
108-
output,
111+
&mut output,
112+
&mut write,
113+
&len,
109114
)?,
110115
(GenericIterable::Set(iter), _, SetType::Set) => validate_iterator(
111116
py,
@@ -116,7 +121,9 @@ impl IntoSetValidator {
116121
&mut checks,
117122
iter.iter().map(Ok),
118123
&self.item_validator,
119-
output,
124+
&mut output,
125+
&mut write,
126+
&len,
120127
)?,
121128
(GenericIterable::FrozenSet(iter), _, SetType::FrozenSet) => validate_iterator(
122129
py,
@@ -127,7 +134,9 @@ impl IntoSetValidator {
127134
&mut checks,
128135
iter.iter().map(Ok),
129136
&self.item_validator,
130-
output,
137+
&mut output,
138+
&mut write,
139+
&len,
131140
)?,
132141
// If not in strict mode we also accept any iterable except str, bytes or mappings
133142
// This may seem counterintuitive since a Mapping is a less generic type than an arbitrary
@@ -151,7 +160,9 @@ impl IntoSetValidator {
151160
&mut checks,
152161
iter,
153162
&self.item_validator,
154-
output,
163+
&mut output,
164+
&mut write,
165+
&len,
155166
)?,
156167
Err(_) => return Err(create_err(input)),
157168
},
@@ -283,32 +294,3 @@ impl Validator for SetValidator {
283294
self.inner.complete(definitions)
284295
}
285296
}
286-
287-
#[allow(clippy::too_many_arguments)]
288-
fn validate_iterator<'s, 'data, V>(
289-
py: Python<'data>,
290-
input: &'data impl Input<'data>,
291-
extra: &'s Extra<'s>,
292-
definitions: &'data Definitions<CombinedValidator>,
293-
recursion_guard: &'s mut RecursionGuard,
294-
checks: &mut IterableValidationChecks<'data>,
295-
iter: impl Iterator<Item = PyResult<&'data V>>,
296-
items_validator: &'s CombinedValidator,
297-
output: &PySet,
298-
) -> ValResult<'data, ()>
299-
where
300-
V: Input<'data> + 'data,
301-
{
302-
for (index, result) in iter.enumerate() {
303-
let value = result.map_err(|e| map_iter_error(py, input, index, e))?;
304-
let result = items_validator
305-
.validate(py, value, extra, definitions, recursion_guard)
306-
.map_err(|e| e.with_outer_location(index.into()));
307-
if let Some(value) = checks.filter_validation_result(result, input)? {
308-
output.add(value)?;
309-
checks.check_output_length(output.len(), input)?;
310-
}
311-
}
312-
checks.finish(input)?;
313-
Ok(())
314-
}

src/validators/tuple.rs

Lines changed: 12 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,9 @@ use pyo3::types::{PyDict, PyList, PyTuple};
55
use crate::build_tools::{is_strict, SchemaDict};
66
use crate::errors::ValLineError;
77
use crate::errors::{ErrorType, ValError, ValResult};
8-
use crate::input::iterator::calculate_output_init_capacity;
9-
use crate::input::iterator::map_iter_error;
108
use crate::input::iterator::IterableValidationChecks;
119
use crate::input::iterator::LengthConstraints;
10+
use crate::input::iterator::{calculate_output_init_capacity, map_iter_error, validate_iterator};
1211
use crate::input::{GenericIterable, Input};
1312
use crate::recursion_guard::RecursionGuard;
1413

@@ -49,35 +48,6 @@ impl BuildValidator for TupleVariableValidator {
4948
}
5049
}
5150

52-
#[allow(clippy::too_many_arguments)]
53-
fn validate_iterator<'s, 'data, V>(
54-
py: Python<'data>,
55-
input: &'data impl Input<'data>,
56-
extra: &'s Extra<'s>,
57-
definitions: &'data Definitions<CombinedValidator>,
58-
recursion_guard: &'s mut RecursionGuard,
59-
checks: &mut IterableValidationChecks<'data>,
60-
iter: impl Iterator<Item = PyResult<&'data V>>,
61-
items_validator: &'s CombinedValidator,
62-
output: &mut Vec<PyObject>,
63-
) -> ValResult<'data, ()>
64-
where
65-
V: Input<'data> + 'data,
66-
{
67-
for (index, result) in iter.enumerate() {
68-
let value = result.map_err(|e| map_iter_error(py, input, index, e))?;
69-
let result = items_validator
70-
.validate(py, value, extra, definitions, recursion_guard)
71-
.map_err(|e| e.with_outer_location(index.into()));
72-
if let Some(value) = checks.filter_validation_result(result, input)? {
73-
output.push(value);
74-
checks.check_output_length(output.len(), input)?;
75-
}
76-
}
77-
checks.finish(input)?;
78-
Ok(())
79-
}
80-
8151
const FIELD_TYPE: &str = "Tuple";
8252

8353
impl Validator for TupleVariableValidator {
@@ -104,6 +74,11 @@ impl Validator for TupleVariableValidator {
10474
let mut checks = IterableValidationChecks::new(false, length_constraints, FIELD_TYPE);
10575

10676
let mut output = Vec::with_capacity(calculate_output_init_capacity(generic_iterable.len(), self.max_length));
77+
let len = |output: &Vec<PyObject>| output.len();
78+
let mut write = |output: &mut Vec<PyObject>, ob: PyObject| {
79+
output.push(ob);
80+
Ok(())
81+
};
10782

10883
match (generic_iterable, strict) {
10984
// Always allow actual lists or JSON arrays
@@ -117,6 +92,8 @@ impl Validator for TupleVariableValidator {
11792
iter.iter().map(Ok),
11893
&self.item_validator,
11994
&mut output,
95+
&mut write,
96+
&len,
12097
)?,
12198
(GenericIterable::Tuple(iter), _) => validate_iterator(
12299
py,
@@ -128,6 +105,8 @@ impl Validator for TupleVariableValidator {
128105
iter.iter().map(Ok),
129106
&self.item_validator,
130107
&mut output,
108+
&mut write,
109+
&len,
131110
)?,
132111
// If not in strict mode we also accept any iterable except str, bytes or mappings
133112
// This may seem counterintuitive since a Mapping is a less generic type than an arbitrary
@@ -151,6 +130,8 @@ impl Validator for TupleVariableValidator {
151130
iter,
152131
&self.item_validator,
153132
&mut output,
133+
&mut write,
134+
&len,
154135
)?,
155136
Err(_) => return Err(ValError::new(ErrorType::TupleType, input)),
156137
},

0 commit comments

Comments
 (0)