Skip to content

Commit

Permalink
remaining associated types (#1238)
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Mar 20, 2024
1 parent d73668f commit 3d2e53e
Show file tree
Hide file tree
Showing 9 changed files with 384 additions and 583 deletions.
81 changes: 42 additions & 39 deletions src/input/input_abstract.rs
Expand Up @@ -11,7 +11,7 @@ use crate::{PyMultiHostUrl, PyUrl};

use super::datetime::{EitherDate, EitherDateTime, EitherTime, EitherTimedelta};
use super::return_enums::{EitherBytes, EitherInt, EitherString};
use super::{EitherFloat, GenericIterable, GenericIterator, ValidationMatch};
use super::{EitherFloat, GenericIterator, ValidationMatch};

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

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

fn validate_tuple<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
if strict {
self.strict_tuple()
} else {
self.lax_tuple()
}
}
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn lax_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.strict_tuple()
}
type Tuple<'a>: ValidatedTuple<'py>
where
Self: 'a;

fn validate_set<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
if strict {
self.strict_set()
} else {
self.lax_set()
}
}
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn lax_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.strict_set()
}
fn validate_tuple(&self, strict: bool) -> ValMatch<Self::Tuple<'_>>;

fn validate_frozenset<'a>(&'a self, strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
if strict {
self.strict_frozenset()
} else {
self.lax_frozenset()
}
}
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>>;
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn lax_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.strict_frozenset()
}
type Set<'a>: ValidatedSet<'py>
where
Self: 'a;

fn validate_set(&self, strict: bool) -> ValMatch<Self::Set<'_>>;

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

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

Expand Down Expand Up @@ -303,14 +276,27 @@ pub trait ValidatedDict<'py> {
) -> ValResult<R>;
}

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

/// For validations from a tuple
pub trait ValidatedTuple<'py> {
type Item: BorrowInput<'py>;
fn len(&self) -> Option<usize>;
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R>;
}

/// For validations from a set
pub trait ValidatedSet<'py> {
type Item: BorrowInput<'py>;
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R>;
}

/// This type is used for inputs which don't support certain types.
/// It implements all the associated traits, but never actually gets called.

Expand Down Expand Up @@ -346,6 +332,23 @@ impl<'py> ValidatedList<'py> for Never {
}
}

impl<'py> ValidatedTuple<'py> for Never {
type Item = Bound<'py, PyAny>;
fn len(&self) -> Option<usize> {
unreachable!()
}
fn iterate<R>(self, _consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
unreachable!()
}
}

impl<'py> ValidatedSet<'py> for Never {
type Item = Bound<'py, PyAny>;
fn iterate<R>(self, _consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
unreachable!()
}
}

impl Arguments<'_> for Never {
type Args = Never;
type Kwargs = Never;
Expand Down
78 changes: 40 additions & 38 deletions src/input/input_json.rs
Expand Up @@ -19,8 +19,8 @@ use super::input_abstract::{ConsumeIterator, Never, ValMatch};
use super::return_enums::ValidationMatch;
use super::shared::{float_as_int, int_as_bool, str_as_bool, str_as_float, str_as_int};
use super::{
Arguments, BorrowInput, EitherBytes, EitherFloat, EitherInt, EitherString, EitherTimedelta, GenericIterable,
GenericIterator, Input, KeywordArgs, PositionalArgs, ValidatedDict, ValidatedList,
Arguments, BorrowInput, EitherBytes, EitherFloat, EitherInt, EitherString, EitherTimedelta, GenericIterator, Input,
KeywordArgs, PositionalArgs, ValidatedDict, ValidatedList, ValidatedSet, ValidatedTuple,
};

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

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

fn validate_tuple<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
type Tuple<'a> = &'a JsonArray;

fn validate_tuple(&self, _strict: bool) -> ValMatch<&JsonArray> {
// just as in set's case, List has to be allowed
match self {
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::TupleType, self)),
}
}
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.validate_tuple(false)
}

fn validate_set<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
type Set<'a> = &'a JsonArray;

fn validate_set(&self, _strict: bool) -> ValMatch<&JsonArray> {
// we allow a list here since otherwise it would be impossible to create a set from JSON
match self {
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::SetType, self)),
}
}
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.validate_set(false)
}

fn validate_frozenset<'a>(&'a self, _strict: bool) -> ValResult<GenericIterable<'a, 'py>> {
fn validate_frozenset(&self, _strict: bool) -> ValMatch<&JsonArray> {
// we allow a list here since otherwise it would be impossible to create a frozenset from JSON
match self {
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
JsonValue::Array(a) => Ok(ValidationMatch::strict(a)),
_ => Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self)),
}
}
#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
self.validate_frozenset(false)
}

fn extract_generic_iterable(&self) -> ValResult<GenericIterable<'_, 'py>> {
match self {
JsonValue::Array(a) => Ok(GenericIterable::JsonArray(a)),
JsonValue::Str(s) => Ok(GenericIterable::JsonString(s)),
JsonValue::Object(object) => Ok(GenericIterable::JsonObject(object)),
_ => Err(ValError::new(ErrorTypeDefaults::IterableType, self)),
}
}

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

type Tuple<'a> = Never;

#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_tuple<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
fn validate_tuple(&self, _strict: bool) -> ValMatch<Never> {
Err(ValError::new(ErrorTypeDefaults::TupleType, self))
}

type Set<'a> = Never;

#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_set<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
fn validate_set(&self, _strict: bool) -> ValMatch<Never> {
Err(ValError::new(ErrorTypeDefaults::SetType, self))
}

#[cfg_attr(has_coverage_attribute, coverage(off))]
fn strict_frozenset<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
Err(ValError::new(ErrorTypeDefaults::FrozenSetType, self))
}

fn extract_generic_iterable<'a>(&'a self) -> ValResult<GenericIterable<'a, 'py>> {
Ok(GenericIterable::JsonString(self))
fn validate_frozenset(&self, _strict: bool) -> ValMatch<Never> {
Err(ValError::new(ErrorTypeDefaults::SetType, self))
}

fn validate_iter(&self) -> ValResult<GenericIterator> {
Expand Down Expand Up @@ -504,6 +487,25 @@ impl<'a, 'py> ValidatedList<'py> for &'a JsonArray {
}
}

impl<'a, 'py> ValidatedTuple<'py> for &'a JsonArray {
type Item = &'a JsonValue;

fn len(&self) -> Option<usize> {
Some(SmallVec::len(self))
}
fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
Ok(consumer.consume_iterator(self.iter().map(Ok)))
}
}

impl<'a, 'py> ValidatedSet<'py> for &'a JsonArray {
type Item = &'a JsonValue;

fn iterate<R>(self, consumer: impl ConsumeIterator<PyResult<Self::Item>, Output = R>) -> ValResult<R> {
Ok(consumer.consume_iterator(self.iter().map(Ok)))
}
}

#[cfg_attr(debug_assertions, derive(Debug))]
pub struct JsonArgs<'a> {
args: Option<&'a [JsonValue]>,
Expand Down

0 comments on commit 3d2e53e

Please sign in to comment.