Skip to content

Commit

Permalink
using enum dispatch (pydantic#41)
Browse files Browse the repository at this point in the history
  • Loading branch information
samuelcolvin authored May 2, 2022
1 parent 916f441 commit bc2c0ec
Show file tree
Hide file tree
Showing 24 changed files with 457 additions and 453 deletions.
13 changes: 13 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ regex = "1.5.5"
strum = { version = "0.24", features = ["derive"] }
strum_macros = "0.24"
serde_json = {version = "1.0.79", features = ["preserve_order"]}
enum_dispatch = "0.3.8"

[lib]
name = "_pydantic_core"
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#![feature(trait_upcasting)]

extern crate core;
extern crate enum_dispatch;
extern crate pyo3;
extern crate regex;
extern crate serde_json;
Expand Down
18 changes: 10 additions & 8 deletions src/validators/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,21 @@ use pyo3::types::PyDict;
use crate::errors::ValResult;
use crate::input::Input;

use super::{validator_boilerplate, Extra, Validator};
use super::{BuildValidator, Extra, ValidateEnum, Validator};

/// This might seem useless, but it's useful in DictValidator to avoid Option<Validator> a lot
#[derive(Debug, Clone)]
pub struct AnyValidator;

impl AnyValidator {
pub const EXPECTED_TYPE: &'static str = "any";
}
impl BuildValidator for AnyValidator {
const EXPECTED_TYPE: &'static str = "any";

impl Validator for AnyValidator {
fn build(_schema: &PyDict, _config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self))
fn build(_schema: &PyDict, _config: Option<&PyDict>) -> PyResult<ValidateEnum> {
Ok(Self.into())
}
}

impl Validator for AnyValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -28,5 +28,7 @@ impl Validator for AnyValidator {
Ok(input.to_py(py))
}

validator_boilerplate!(Self::EXPECTED_TYPE);
fn get_name(&self, _py: Python) -> String {
Self::EXPECTED_TYPE.to_string()
}
}
34 changes: 20 additions & 14 deletions src/validators/bool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,24 +5,24 @@ use crate::build_tools::is_strict;
use crate::errors::ValResult;
use crate::input::Input;

use super::{validator_boilerplate, Extra, Validator};
use super::{BuildValidator, Extra, ValidateEnum, Validator};

#[derive(Debug, Clone)]
pub struct BoolValidator;

impl BoolValidator {
pub const EXPECTED_TYPE: &'static str = "bool";
}
impl BuildValidator for BoolValidator {
const EXPECTED_TYPE: &'static str = "bool";

impl Validator for BoolValidator {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<ValidateEnum> {
if is_strict(schema, config)? {
StrictBoolValidator::build(schema, config)
StrictBoolValidator::build()
} else {
Ok(Box::new(Self {}))
Ok(Self.into())
}
}
}

impl Validator for BoolValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -43,17 +43,21 @@ impl Validator for BoolValidator {
Ok(input.strict_bool()?.into_py(py))
}

validator_boilerplate!(Self::EXPECTED_TYPE);
fn get_name(&self, _py: Python) -> String {
Self::EXPECTED_TYPE.to_string()
}
}

#[derive(Debug, Clone)]
struct StrictBoolValidator;
pub struct StrictBoolValidator;

impl Validator for StrictBoolValidator {
fn build(_schema: &PyDict, _config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self {}))
impl StrictBoolValidator {
pub fn build() -> PyResult<ValidateEnum> {
Ok(Self.into())
}
}

impl Validator for StrictBoolValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -63,5 +67,7 @@ impl Validator for StrictBoolValidator {
Ok(input.strict_bool()?.into_py(py))
}

validator_boilerplate!("strict-bool");
fn get_name(&self, _py: Python) -> String {
"strict-bool".to_string()
}
}
36 changes: 16 additions & 20 deletions src/validators/dict.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,41 @@ use crate::errors::{as_internal, context, err_val_error, ErrorKind, InputValue,
use crate::input::{DictInput, Input, ToLocItem};

use super::any::AnyValidator;
use super::{build_validator, Extra, Validator, ValidatorArc};
use super::{build_validator, BuildValidator, Extra, ValidateEnum, Validator, ValidatorArc};

#[derive(Debug, Clone)]
pub struct DictValidator {
strict: bool,
key_validator: Box<dyn Validator>,
value_validator: Box<dyn Validator>,
key_validator: Box<ValidateEnum>,
value_validator: Box<ValidateEnum>,
min_items: Option<usize>,
max_items: Option<usize>,
try_instance_as_dict: bool,
}

impl DictValidator {
pub const EXPECTED_TYPE: &'static str = "dict";
}
impl BuildValidator for DictValidator {
const EXPECTED_TYPE: &'static str = "dict";

impl Validator for DictValidator {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<ValidateEnum> {
Ok(Self {
strict: is_strict(schema, config)?,
key_validator: match schema.get_item("keys") {
Some(schema) => build_validator(schema, config)?.0,
None => AnyValidator::build(schema, config)?,
Some(schema) => Box::new(build_validator(schema, config)?.0),
None => Box::new(AnyValidator::build(schema, config)?),
},
value_validator: match schema.get_item("values") {
Some(d) => build_validator(d, config)?.0,
None => AnyValidator::build(schema, config)?,
Some(d) => Box::new(build_validator(d, config)?.0),
None => Box::new(AnyValidator::build(schema, config)?),
},
min_items: schema.get_as("min_items")?,
max_items: schema.get_as("max_items")?,
try_instance_as_dict: schema.get_as("try_instance_as_dict")?.unwrap_or(false),
}))
}
.into())
}
}

impl Validator for DictValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand Down Expand Up @@ -70,11 +71,6 @@ impl Validator for DictValidator {
fn get_name(&self, _py: Python) -> String {
Self::EXPECTED_TYPE.to_string()
}

#[no_coverage]
fn clone_dyn(&self) -> Box<dyn Validator> {
Box::new(self.clone())
}
}

impl DictValidator {
Expand Down Expand Up @@ -126,7 +122,7 @@ impl DictValidator {

fn apply_validator<'s, 'data>(
py: Python<'data>,
validator: &'s dyn Validator,
validator: &'s ValidateEnum,
errors: &mut Vec<ValLineError<'data>>,
input: &'data dyn Input,
key: &'data dyn Input,
Expand Down
63 changes: 36 additions & 27 deletions src/validators/float.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,15 @@ use crate::build_tools::{is_strict, SchemaDict};
use crate::errors::{context, err_val_error, ErrorKind, InputValue, ValResult};
use crate::input::Input;

use super::{validator_boilerplate, Extra, Validator};
use super::{BuildValidator, Extra, ValidateEnum, Validator};

#[derive(Debug, Clone)]
pub struct FloatValidator;

impl FloatValidator {
pub const EXPECTED_TYPE: &'static str = "float";
}
impl BuildValidator for FloatValidator {
const EXPECTED_TYPE: &'static str = "float";

impl Validator for FloatValidator {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<ValidateEnum> {
let use_constrained = schema.get_item("multiple_of").is_some()
|| schema.get_item("le").is_some()
|| schema.get_item("lt").is_some()
Expand All @@ -24,12 +22,14 @@ impl Validator for FloatValidator {
if use_constrained {
ConstrainedFloatValidator::build(schema, config)
} else if is_strict(schema, config)? {
StrictFloatValidator::build(schema, config)
StrictFloatValidator::build()
} else {
Ok(Box::new(Self))
Ok(Self.into())
}
}
}

impl Validator for FloatValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -48,17 +48,21 @@ impl Validator for FloatValidator {
Ok(input.strict_float()?.into_py(py))
}

validator_boilerplate!(Self::EXPECTED_TYPE);
fn get_name(&self, _py: Python) -> String {
Self::EXPECTED_TYPE.to_string()
}
}

#[derive(Debug, Clone)]
struct StrictFloatValidator;
pub struct StrictFloatValidator;

impl Validator for StrictFloatValidator {
fn build(_schema: &PyDict, _config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self))
impl StrictFloatValidator {
pub fn build() -> PyResult<ValidateEnum> {
Ok(Self.into())
}
}

impl Validator for StrictFloatValidator {
fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -68,11 +72,13 @@ impl Validator for StrictFloatValidator {
Ok(input.strict_float()?.into_py(py))
}

validator_boilerplate!("strict-float");
fn get_name(&self, _py: Python) -> String {
"strict-float".to_string()
}
}

#[derive(Debug, Clone)]
struct ConstrainedFloatValidator {
pub struct ConstrainedFloatValidator {
strict: bool,
multiple_of: Option<f64>,
le: Option<f64>,
Expand All @@ -82,17 +88,6 @@ struct ConstrainedFloatValidator {
}

impl Validator for ConstrainedFloatValidator {
fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<Box<dyn Validator>> {
Ok(Box::new(Self {
strict: is_strict(schema, config)?,
multiple_of: schema.get_as("multiple_of")?,
le: schema.get_as("le")?,
lt: schema.get_as("lt")?,
ge: schema.get_as("ge")?,
gt: schema.get_as("gt")?,
}))
}

fn validate<'s, 'data>(
&'s self,
py: Python<'data>,
Expand All @@ -115,10 +110,24 @@ impl Validator for ConstrainedFloatValidator {
self._validation_logic(py, input, input.strict_float()?)
}

validator_boilerplate!("constrained-float");
fn get_name(&self, _py: Python) -> String {
"constrained-float".to_string()
}
}

impl ConstrainedFloatValidator {
pub fn build(schema: &PyDict, config: Option<&PyDict>) -> PyResult<ValidateEnum> {
Ok(Self {
strict: is_strict(schema, config)?,
multiple_of: schema.get_as("multiple_of")?,
le: schema.get_as("le")?,
lt: schema.get_as("lt")?,
ge: schema.get_as("ge")?,
gt: schema.get_as("gt")?,
}
.into())
}

fn _validation_logic<'s, 'data>(
&'s self,
py: Python<'data>,
Expand Down
Loading

0 comments on commit bc2c0ec

Please sign in to comment.