Skip to content

Commit 5f14973

Browse files
committed
validators never need to be cloned
1 parent cddcc71 commit 5f14973

25 files changed

+69
-58
lines changed

src/py_gc.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use ahash::AHashMap;
24
use enum_dispatch::enum_dispatch;
35
use pyo3::{AsPyPointer, Py, PyTraverseError, PyVisit};
@@ -35,6 +37,12 @@ impl<T: PyGcTraverse> PyGcTraverse for AHashMap<String, T> {
3537
}
3638
}
3739

40+
impl<T: PyGcTraverse> PyGcTraverse for Arc<T> {
41+
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
42+
T::py_gc_traverse(self, visit)
43+
}
44+
}
45+
3846
impl<T: PyGcTraverse> PyGcTraverse for Box<T> {
3947
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
4048
T::py_gc_traverse(self, visit)

src/validators/arguments.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::tools::SchemaDict;
1515
use super::validation_state::ValidationState;
1616
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1717

18-
#[derive(Debug, Clone)]
18+
#[derive(Debug)]
1919
struct Parameter {
2020
positional: bool,
2121
name: String,
@@ -24,7 +24,7 @@ struct Parameter {
2424
validator: CombinedValidator,
2525
}
2626

27-
#[derive(Debug, Clone)]
27+
#[derive(Debug)]
2828
pub struct ArgumentsValidator {
2929
parameters: Vec<Parameter>,
3030
positional_params_count: usize,

src/validators/call.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::tools::SchemaDict;
1111
use super::validation_state::ValidationState;
1212
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Debug)]
1515
pub struct CallValidator {
1616
function: PyObject,
1717
arguments_validator: Box<CombinedValidator>,

src/validators/chain.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::tools::SchemaDict;
1010
use super::validation_state::ValidationState;
1111
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1212

13-
#[derive(Debug, Clone)]
13+
#[derive(Debug)]
1414
pub struct ChainValidator {
1515
steps: Vec<CombinedValidator>,
1616
name: String,

src/validators/custom_error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ impl CustomError {
5757
}
5858
}
5959

60-
#[derive(Debug, Clone)]
60+
#[derive(Debug)]
6161
pub struct CustomErrorValidator {
6262
validator: Box<CombinedValidator>,
6363
custom_error: CustomError,

src/validators/dataclass.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ use super::{
1919
build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Extra, ValidationState, Validator,
2020
};
2121

22-
#[derive(Debug, Clone)]
22+
#[derive(Debug)]
2323
struct Field {
2424
kw_only: bool,
2525
name: String,
@@ -30,7 +30,7 @@ struct Field {
3030
frozen: bool,
3131
}
3232

33-
#[derive(Debug, Clone)]
33+
#[derive(Debug)]
3434
pub struct DataclassArgsValidator {
3535
fields: Vec<Field>,
3636
positional_count: usize,
@@ -441,7 +441,7 @@ impl Validator for DataclassArgsValidator {
441441
}
442442
}
443443

444-
#[derive(Debug, Clone)]
444+
#[derive(Debug)]
445445
pub struct DataclassValidator {
446446
strict: bool,
447447
validator: Box<CombinedValidator>,

src/validators/dict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use super::any::AnyValidator;
1616
use super::list::length_check;
1717
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, ValidationState, Validator};
1818

19-
#[derive(Debug, Clone)]
19+
#[derive(Debug)]
2020
pub struct DictValidator {
2121
strict: bool,
2222
key_validator: Box<CombinedValidator>,

src/validators/frozenset.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use super::set::set_build;
1010
use super::validation_state::ValidationState;
1111
use super::{BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1212

13-
#[derive(Debug, Clone)]
13+
#[derive(Debug)]
1414
pub struct FrozenSetValidator {
1515
strict: bool,
1616
item_validator: Box<CombinedValidator>,

src/validators/function.rs

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::sync::Arc;
2+
13
use pyo3::exceptions::{PyAssertionError, PyTypeError, PyValueError};
24
use pyo3::prelude::*;
35
use pyo3::types::{PyAny, PyDict, PyString};
@@ -130,7 +132,7 @@ macro_rules! impl_validator {
130132
};
131133
}
132134

133-
#[derive(Debug, Clone)]
135+
#[derive(Debug)]
134136
pub struct FunctionBeforeValidator {
135137
validator: Box<CombinedValidator>,
136138
func: PyObject,
@@ -163,7 +165,7 @@ impl FunctionBeforeValidator {
163165

164166
impl_validator!(FunctionBeforeValidator);
165167

166-
#[derive(Debug, Clone)]
168+
#[derive(Debug)]
167169
pub struct FunctionAfterValidator {
168170
validator: Box<CombinedValidator>,
169171
func: PyObject,
@@ -264,9 +266,9 @@ impl Validator for FunctionPlainValidator {
264266
}
265267
}
266268

267-
#[derive(Debug, Clone)]
269+
#[derive(Debug)]
268270
pub struct FunctionWrapValidator {
269-
validator: Box<CombinedValidator>,
271+
validator: Arc<CombinedValidator>,
270272
func: PyObject,
271273
config: PyObject,
272274
name: String,
@@ -290,7 +292,7 @@ impl BuildValidator for FunctionWrapValidator {
290292
let hide_input_in_errors: bool = config.get_as(intern!(py, "hide_input_in_errors"))?.unwrap_or(false);
291293
let validation_error_cause: bool = config.get_as(intern!(py, "validation_error_cause"))?.unwrap_or(false);
292294
Ok(Self {
293-
validator: Box::new(validator),
295+
validator: Arc::new(validator),
294296
func: function_info.function.clone(),
295297
config: match config {
296298
Some(c) => c.into(),
@@ -341,7 +343,7 @@ impl Validator for FunctionWrapValidator {
341343
validator: InternalValidator::new(
342344
py,
343345
"ValidatorCallable",
344-
&self.validator,
346+
self.validator.clone(),
345347
state,
346348
self.hide_input_in_errors,
347349
self.validation_error_cause,
@@ -367,7 +369,7 @@ impl Validator for FunctionWrapValidator {
367369
validator: InternalValidator::new(
368370
py,
369371
"AssignmentValidatorCallable",
370-
&self.validator,
372+
self.validator.clone(),
371373
state,
372374
self.hide_input_in_errors,
373375
self.validation_error_cause,
@@ -396,7 +398,7 @@ impl Validator for FunctionWrapValidator {
396398
}
397399

398400
#[pyclass(module = "pydantic_core._pydantic_core")]
399-
#[derive(Debug, Clone)]
401+
#[derive(Debug)]
400402
struct ValidatorCallable {
401403
validator: InternalValidator,
402404
}
@@ -428,7 +430,7 @@ impl ValidatorCallable {
428430
}
429431

430432
#[pyclass(module = "pydantic_core._pydantic_core")]
431-
#[derive(Debug, Clone)]
433+
#[derive(Debug)]
432434
struct AssignmentValidatorCallable {
433435
updated_field_name: String,
434436
updated_field_value: Py<PyAny>,

src/validators/generator.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::fmt;
2+
use std::sync::Arc;
23

34
use pyo3::prelude::*;
45
use pyo3::types::PyDict;
@@ -14,7 +15,7 @@ use super::{BuildValidator, CombinedValidator, DefinitionsBuilder, Extra, InputT
1415

1516
#[derive(Debug, Clone)]
1617
pub struct GeneratorValidator {
17-
item_validator: Option<Box<CombinedValidator>>,
18+
item_validator: Option<Arc<CombinedValidator>>,
1819
min_length: Option<usize>,
1920
max_length: Option<usize>,
2021
name: String,
@@ -30,7 +31,7 @@ impl BuildValidator for GeneratorValidator {
3031
config: Option<&PyDict>,
3132
definitions: &mut DefinitionsBuilder<CombinedValidator>,
3233
) -> PyResult<CombinedValidator> {
33-
let item_validator = get_items_schema(schema, config, definitions)?;
34+
let item_validator = get_items_schema(schema, config, definitions)?.map(Arc::new);
3435
let name = match item_validator {
3536
Some(ref v) => format!("{}[{}]", Self::EXPECTED_TYPE, v.get_name()),
3637
None => format!("{}[any]", Self::EXPECTED_TYPE),
@@ -67,7 +68,7 @@ impl Validator for GeneratorValidator {
6768
InternalValidator::new(
6869
py,
6970
"ValidatorIterator",
70-
v,
71+
v.clone(),
7172
state,
7273
self.hide_input_in_errors,
7374
self.validation_error_cause,
@@ -106,7 +107,7 @@ impl Validator for GeneratorValidator {
106107
}
107108

108109
#[pyclass(module = "pydantic_core._pydantic_core")]
109-
#[derive(Debug, Clone)]
110+
#[derive(Debug)]
110111
struct ValidatorIterator {
111112
iterator: GenericIterator,
112113
validator: Option<InternalValidator>,
@@ -213,12 +214,11 @@ impl ValidatorIterator {
213214
}
214215
}
215216

216-
/// Cloneable validator wrapper for use in generators in functions, this can be passed back to python
217+
/// Owned validator wrapper for use in generators in functions, this can be passed back to python
217218
/// mid-validation
218-
#[derive(Clone)]
219219
pub struct InternalValidator {
220220
name: String,
221-
validator: CombinedValidator,
221+
validator: Arc<CombinedValidator>,
222222
// TODO, do we need data?
223223
data: Option<Py<PyDict>>,
224224
strict: Option<bool>,
@@ -241,15 +241,15 @@ impl InternalValidator {
241241
pub fn new(
242242
py: Python,
243243
name: &str,
244-
validator: &CombinedValidator,
244+
validator: Arc<CombinedValidator>,
245245
state: &ValidationState,
246246
hide_input_in_errors: bool,
247247
validation_error_cause: bool,
248248
) -> Self {
249249
let extra = state.extra();
250250
Self {
251251
name: name.to_string(),
252-
validator: validator.clone(),
252+
validator,
253253
data: extra.data.map(|d| d.into_py(py)),
254254
strict: extra.strict,
255255
from_attributes: extra.from_attributes,

src/validators/json.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::tools::SchemaDict;
99
use super::ValidationState;
1010
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1111

12-
#[derive(Debug, Clone)]
12+
#[derive(Debug)]
1313
pub struct JsonValidator {
1414
validator: Option<Box<CombinedValidator>>,
1515
name: String,

src/validators/json_or_python.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use super::InputType;
1111
use super::ValidationState;
1212
use super::{build_validator, BuildValidator, CombinedValidator, Validator};
1313

14-
#[derive(Debug, Clone)]
14+
#[derive(Debug)]
1515
pub struct JsonOrPython {
1616
json: Box<CombinedValidator>,
1717
python: Box<CombinedValidator>,

src/validators/lax_or_strict.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::tools::SchemaDict;
1010
use super::ValidationState;
1111
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, Validator};
1212

13-
#[derive(Debug, Clone)]
13+
#[derive(Debug)]
1414
pub struct LaxOrStrictValidator {
1515
strict: bool,
1616
lax_validator: Box<CombinedValidator>,

src/validators/list.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::tools::SchemaDict;
99

1010
use super::{build_validator, BuildValidator, CombinedValidator, DefinitionsBuilder, ValidationState, Validator};
1111

12-
#[derive(Debug, Clone)]
12+
#[derive(Debug)]
1313
pub struct ListValidator {
1414
strict: bool,
1515
item_validator: Option<Box<CombinedValidator>>,
@@ -22,13 +22,13 @@ pub fn get_items_schema(
2222
schema: &PyDict,
2323
config: Option<&PyDict>,
2424
definitions: &mut DefinitionsBuilder<CombinedValidator>,
25-
) -> PyResult<Option<Box<CombinedValidator>>> {
25+
) -> PyResult<Option<CombinedValidator>> {
2626
match schema.get_item(pyo3::intern!(schema.py(), "items_schema")) {
2727
Some(d) => {
2828
let validator = build_validator(d, config, definitions)?;
2929
match validator {
3030
CombinedValidator::Any(_) => Ok(None),
31-
_ => Ok(Some(Box::new(validator))),
31+
_ => Ok(Some(validator)),
3232
}
3333
}
3434
None => Ok(None),
@@ -100,7 +100,7 @@ impl BuildValidator for ListValidator {
100100
definitions: &mut DefinitionsBuilder<CombinedValidator>,
101101
) -> PyResult<CombinedValidator> {
102102
let py = schema.py();
103-
let item_validator = get_items_schema(schema, config, definitions)?;
103+
let item_validator = get_items_schema(schema, config, definitions)?.map(Box::new);
104104
Ok(Self {
105105
strict: crate::build_tools::is_strict(schema, config)?,
106106
item_validator,

src/validators/literal.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ struct BoolLiteral {
2222
}
2323

2424
#[derive(Debug, Clone)]
25-
pub struct LiteralLookup<T: Clone + Debug> {
25+
pub struct LiteralLookup<T: Debug> {
2626
// Specialized lookups for ints, bools and strings because they
2727
// (1) are easy to convert between Rust and Python
2828
// (2) hashing them in Rust is very fast
@@ -35,7 +35,7 @@ pub struct LiteralLookup<T: Clone + Debug> {
3535
pub values: Vec<T>,
3636
}
3737

38-
impl<T: Clone + Debug> LiteralLookup<T> {
38+
impl<T: Debug> LiteralLookup<T> {
3939
pub fn new<'py>(py: Python<'py>, expected: impl Iterator<Item = (&'py PyAny, T)>) -> PyResult<Self> {
4040
let mut expected_int = AHashMap::new();
4141
let mut expected_str: AHashMap<String, usize> = AHashMap::new();
@@ -135,7 +135,7 @@ impl<T: Clone + Debug> LiteralLookup<T> {
135135
}
136136
}
137137

138-
impl<T: PyGcTraverse + Clone + Debug> PyGcTraverse for LiteralLookup<T> {
138+
impl<T: PyGcTraverse + Debug> PyGcTraverse for LiteralLookup<T> {
139139
fn py_gc_traverse(&self, visit: &PyVisit<'_>) -> Result<(), PyTraverseError> {
140140
self.expected_py.py_gc_traverse(visit)?;
141141
self.values.py_gc_traverse(visit)?;

src/validators/mod.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ impl PySome {
9898
}
9999

100100
#[pyclass(module = "pydantic_core._pydantic_core")]
101-
#[derive(Debug, Clone)]
101+
#[derive(Debug)]
102102
pub struct SchemaValidator {
103103
validator: CombinedValidator,
104104
definitions: Definitions<CombinedValidator>,
@@ -141,9 +141,10 @@ impl SchemaValidator {
141141
})
142142
}
143143

144-
pub fn __reduce__(&self, py: Python) -> PyResult<PyObject> {
145-
let args = (self.schema.as_ref(py),);
146-
let cls = Py::new(py, self.clone())?.getattr(py, "__class__")?;
144+
pub fn __reduce__(slf: &PyCell<Self>) -> PyResult<PyObject> {
145+
let py = slf.py();
146+
let args = (slf.try_borrow()?.schema.to_object(py),);
147+
let cls = slf.getattr("__class__")?;
147148
Ok((cls, args).into_py(py))
148149
}
149150

@@ -598,7 +599,7 @@ impl<'a> Extra<'a> {
598599
}
599600
}
600601

601-
#[derive(Debug, Clone)]
602+
#[derive(Debug)]
602603
#[enum_dispatch(PyGcTraverse)]
603604
pub enum CombinedValidator {
604605
// typed dict e.g. heterogeneous dicts or simply a model
@@ -694,7 +695,7 @@ pub enum CombinedValidator {
694695
/// This trait must be implemented by all validators, it allows various validators to be accessed consistently,
695696
/// validators defined in `build_validator` also need `EXPECTED_TYPE` as a const, but that can't be part of the trait
696697
#[enum_dispatch(CombinedValidator)]
697-
pub trait Validator: Send + Sync + Clone + Debug {
698+
pub trait Validator: Send + Sync + Debug {
698699
/// Do the actual validation for this schema/type
699700
fn validate<'data>(
700701
&self,

0 commit comments

Comments
 (0)