Skip to content

Commit 3d2e53e

Browse files
authored
remaining associated types (#1238)
1 parent d73668f commit 3d2e53e

File tree

9 files changed

+384
-583
lines changed

9 files changed

+384
-583
lines changed

src/input/input_abstract.rs

+42-39
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{PyMultiHostUrl, PyUrl};
1111

1212
use super::datetime::{EitherDate, EitherDateTime, EitherTime, EitherTimedelta};
1313
use super::return_enums::{EitherBytes, EitherInt, EitherString};
14-
use super::{EitherFloat, GenericIterable, GenericIterator, ValidationMatch};
14+
use super::{EitherFloat, GenericIterator, ValidationMatch};
1515

1616
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
1717
pub enum InputType {
@@ -166,46 +166,19 @@ pub trait Input<'py>: fmt::Debug + ToPyObject {
166166

167167
fn validate_list(&self, strict: bool) -> ValMatch<Self::List<'_>>;
168168

169-
fn validate_tuple<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
170-
if strict {
171-
self.strict_tuple()
172-
} else {
173-
self.lax_tuple()
174-
}
175-
}
176-
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
177-
#[cfg_attr(has_coverage_attribute, coverage(off))]
178-
fn lax_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
179-
self.strict_tuple()
180-
}
169+
type Tuple<'a>: ValidatedTuple<'py>
170+
where
171+
Self: 'a;
181172

182-
fn validate_set<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
183-
if strict {
184-
self.strict_set()
185-
} else {
186-
self.lax_set()
187-
}
188-
}
189-
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
190-
#[cfg_attr(has_coverage_attribute, coverage(off))]
191-
fn lax_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
192-
self.strict_set()
193-
}
173+
fn validate_tuple(&self, strict: bool) -> ValMatch<Self::Tuple<'_>>;
194174

195-
fn validate_frozenset<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
196-
if strict {
197-
self.strict_frozenset()
198-
} else {
199-
self.lax_frozenset()
200-
}
201-
}
202-
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
203-
#[cfg_attr(has_coverage_attribute, coverage(off))]
204-
fn lax_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
205-
self.strict_frozenset()
206-
}
175+
type Set<'a>: ValidatedSet<'py>
176+
where
177+
Self: 'a;
178+
179+
fn validate_set(&self, strict: bool) -> ValMatch<Self::Set<'_>>;
207180

208-
fn extract_generic_iterable<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
181+
fn validate_frozenset(&self, strict: bool) -> ValMatch<Self::Set<'_>>;
209182

210183
fn validate_iter(&self) -> ValResult<GenericIterator>;
211184

@@ -303,14 +276,27 @@ pub trait ValidatedDict<'py> {
303276
) -> ValResult<R>;
304277
}
305278

306-
// Optimization pathway for inputs which are already python lists
279+
/// For validations from a list
307280
pub trait ValidatedList<'py> {
308281
type Item: BorrowInput<'py>;
309282
fn len(&self) -> Option<usize>;
310283
fn as_py_list(&self) -> Option<&Bound<'py, PyList>>;
311284
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R>;
312285
}
313286

287+
/// For validations from a tuple
288+
pub trait ValidatedTuple<'py> {
289+
type Item: BorrowInput<'py>;
290+
fn len(&self) -> Option<usize>;
291+
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R>;
292+
}
293+
294+
/// For validations from a set
295+
pub trait ValidatedSet<'py> {
296+
type Item: BorrowInput<'py>;
297+
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R>;
298+
}
299+
314300
/// This type is used for inputs which don't support certain types.
315301
/// It implements all the associated traits, but never actually gets called.
316302
@@ -346,6 +332,23 @@ impl<'py> ValidatedList<'py> for Never {
346332
}
347333
}
348334

335+
impl<'py> ValidatedTuple<'py> for Never {
336+
type Item = Bound<'py, PyAny>;
337+
fn len(&self) -> Option<usize> {
338+
unreachable!()
339+
}
340+
fn iterate<R>(self, _consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
341+
unreachable!()
342+
}
343+
}
344+
345+
impl<'py> ValidatedSet<'py> for Never {
346+
type Item = Bound<'py, PyAny>;
347+
fn iterate<R>(self, _consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
348+
unreachable!()
349+
}
350+
}
351+
349352
impl Arguments<'_> for Never {
350353
type Args = Never;
351354
type Kwargs = Never;

src/input/input_json.rs

+40-38
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,8 @@ use super::input_abstract::{ConsumeIterator, Never, ValMatch};
1919
use super::return_enums::ValidationMatch;
2020
use super::shared::{float_as_int, int_as_bool, str_as_bool, str_as_float, str_as_int};
2121
use super::{
22-
Arguments, BorrowInput, EitherBytes, EitherFloat, EitherInt, EitherString, EitherTimedelta, GenericIterable,
23-
GenericIterator, Input, KeywordArgs, PositionalArgs, ValidatedDict, ValidatedList,
22+
Arguments, BorrowInput, EitherBytes, EitherFloat, EitherInt, EitherString, EitherTimedelta, GenericIterator, Input,
23+
KeywordArgs, PositionalArgs, ValidatedDict, ValidatedList, ValidatedSet, ValidatedTuple,
2424
};
2525

2626
/// This is required but since JSON object keys are always strings, I don't think it can be called
@@ -185,55 +185,38 @@ impl<'py> Input<'py> for JsonValue {
185185

186186
fn validate_list(&self, _strict: bool) -> ValMatch<&JsonArray> {
187187
match self {
188-
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
188+
JsonValue::Array(a) => Ok(ValidationMatch::exact(a)),
189189
_ => Err(ValError::new(ErrorTypeDefaults::ListType, self)),
190190
}
191191
}
192192

193-
fn validate_tuple<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
193+
type Tuple<'a> = &'a JsonArray;
194+
195+
fn validate_tuple(&self, _strict: bool) -> ValMatch<&JsonArray> {
194196
// just as in set's case, List has to be allowed
195197
match self {
196-
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
198+
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
197199
_ => Err(ValError::new(ErrorTypeDefaults::TupleType, self)),
198200
}
199201
}
200-
#[cfg_attr(has_coverage_attribute, coverage(off))]
201-
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
202-
self.validate_tuple(false)
203-
}
204202

205-
fn validate_set<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
203+
type Set<'a> = &'a JsonArray;
204+
205+
fn validate_set(&self, _strict: bool) -> ValMatch<&JsonArray> {
206206
// we allow a list here since otherwise it would be impossible to create a set from JSON
207207
match self {
208-
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
208+
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
209209
_ => Err(ValError::new(ErrorTypeDefaults::SetType, self)),
210210
}
211211
}
212-
#[cfg_attr(has_coverage_attribute, coverage(off))]
213-
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
214-
self.validate_set(false)
215-
}
216212

217-
fn validate_frozenset<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
213+
fn validate_frozenset(&self, _strict: bool) -> ValMatch<&JsonArray> {
218214
// we allow a list here since otherwise it would be impossible to create a frozenset from JSON
219215
match self {
220-
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
216+
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
221217
_ => Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self)),
222218
}
223219
}
224-
#[cfg_attr(has_coverage_attribute, coverage(off))]
225-
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
226-
self.validate_frozenset(false)
227-
}
228-
229-
fn extract_generic_iterable(&self) -> ValResult<GenericIterable<'_, 'py>> {
230-
match self {
231-
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
232-
JsonValue::Str(s) => Ok(GenericIterable::JsonString(s)),
233-
JsonValue::Object(object) => Ok(GenericIterable::JsonObject(object)),
234-
_ => Err(ValError::new(ErrorTypeDefaults::IterableType, self)),
235-
}
236-
}
237220

238221
fn validate_iter(&self) -> ValResult<GenericIterator> {
239222
match self {
@@ -392,23 +375,23 @@ impl<'py> Input<'py> for str {
392375
Err(ValError::new(ErrorTypeDefaults::ListType, self))
393376
}
394377

378+
type Tuple<'a> = Never;
379+
395380
#[cfg_attr(has_coverage_attribute, coverage(off))]
396-
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
381+
fn validate_tuple(&self, _strict: bool) -> ValMatch<Never> {
397382
Err(ValError::new(ErrorTypeDefaults::TupleType, self))
398383
}
399384

385+
type Set<'a> = Never;
386+
400387
#[cfg_attr(has_coverage_attribute, coverage(off))]
401-
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
388+
fn validate_set(&self, _strict: bool) -> ValMatch<Never> {
402389
Err(ValError::new(ErrorTypeDefaults::SetType, self))
403390
}
404391

405392
#[cfg_attr(has_coverage_attribute, coverage(off))]
406-
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
407-
Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self))
408-
}
409-
410-
fn extract_generic_iterable<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
411-
Ok(GenericIterable::JsonString(self))
393+
fn validate_frozenset(&self, _strict: bool) -> ValMatch<Never> {
394+
Err(ValError::new(ErrorTypeDefaults::SetType, self))
412395
}
413396

414397
fn validate_iter(&self) -> ValResult<GenericIterator> {
@@ -504,6 +487,25 @@ impl<'a, 'py> ValidatedList<'py> for &'a JsonArray {
504487
}
505488
}
506489

490+
impl<'a, 'py> ValidatedTuple<'py> for &'a JsonArray {
491+
type Item = &'a JsonValue;
492+
493+
fn len(&self) -> Option<usize> {
494+
Some(SmallVec::len(self))
495+
}
496+
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
497+
Ok(consumer.consume_iterator(self.iter().map(Ok)))
498+
}
499+
}
500+
501+
impl<'a, 'py> ValidatedSet<'py> for &'a JsonArray {
502+
type Item = &'a JsonValue;
503+
504+
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
505+
Ok(consumer.consume_iterator(self.iter().map(Ok)))
506+
}
507+
}
508+
507509
#[cfg_attr(debug_assertions, derive(Debug))]
508510
pub struct JsonArgs<'a> {
509511
args: Option<&'a [JsonValue]>,

0 commit comments

Comments
 (0)