From 7368c1f760748349c6eb8a02438e1c4b9aa95314 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Tue, 13 Aug 2024 01:06:22 +0100 Subject: [PATCH] stop clone-ing serializers (#1402) --- src/serializers/computed_fields.rs | 4 ++-- src/serializers/fields.rs | 4 ++-- src/serializers/infer.rs | 2 +- src/serializers/shared.rs | 4 ++-- src/serializers/type_serializers/any.rs | 12 +++++++++++- src/serializers/type_serializers/bytes.rs | 2 +- src/serializers/type_serializers/dataclass.rs | 2 +- .../type_serializers/datetime_etc.rs | 2 +- src/serializers/type_serializers/decimal.rs | 2 +- .../type_serializers/definitions.rs | 2 +- src/serializers/type_serializers/dict.rs | 2 +- src/serializers/type_serializers/enum_.rs | 2 +- src/serializers/type_serializers/float.rs | 2 +- src/serializers/type_serializers/format.rs | 4 ++-- src/serializers/type_serializers/function.rs | 18 +++++++++--------- src/serializers/type_serializers/generator.rs | 16 ++++++++-------- src/serializers/type_serializers/json.rs | 2 +- .../type_serializers/json_or_python.rs | 2 +- src/serializers/type_serializers/list.rs | 2 +- src/serializers/type_serializers/literal.rs | 2 +- src/serializers/type_serializers/model.rs | 2 +- src/serializers/type_serializers/nullable.rs | 2 +- .../type_serializers/set_frozenset.rs | 2 +- src/serializers/type_serializers/simple.rs | 4 ++-- src/serializers/type_serializers/string.rs | 2 +- src/serializers/type_serializers/timedelta.rs | 2 +- src/serializers/type_serializers/tuple.rs | 2 +- src/serializers/type_serializers/typed_dict.rs | 2 +- src/serializers/type_serializers/union.rs | 2 +- src/serializers/type_serializers/url.rs | 2 +- src/serializers/type_serializers/uuid.rs | 2 +- .../type_serializers/with_default.rs | 2 +- 32 files changed, 62 insertions(+), 52 deletions(-) diff --git a/src/serializers/computed_fields.rs b/src/serializers/computed_fields.rs index 2d80d4f61..0cfa2d4d1 100644 --- a/src/serializers/computed_fields.rs +++ b/src/serializers/computed_fields.rs @@ -14,7 +14,7 @@ use crate::tools::SchemaDict; use super::errors::py_err_se_err; use super::Extra; -#[derive(Debug, Clone)] +#[derive(Debug)] pub(super) struct ComputedFields(Vec); impl ComputedFields { @@ -109,7 +109,7 @@ impl ComputedFields { } } -#[derive(Debug, Clone)] +#[derive(Debug)] struct ComputedField { property_name: String, property_name_py: Py, diff --git a/src/serializers/fields.rs b/src/serializers/fields.rs index f4f8910eb..87c34d364 100644 --- a/src/serializers/fields.rs +++ b/src/serializers/fields.rs @@ -20,7 +20,7 @@ use super::shared::PydanticSerializer; use super::shared::{CombinedSerializer, TypeSerializer}; /// representation of a field for serialization -#[derive(Debug, Clone)] +#[derive(Debug)] pub(super) struct SerField { pub key_py: Py, pub alias: Option, @@ -93,7 +93,7 @@ pub(super) enum FieldsMode { } /// General purpose serializer for fields - used by dataclasses, models and typed_dicts -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct GeneralFieldsSerializer { fields: AHashMap, computed_fields: Option, diff --git a/src/serializers/infer.rs b/src/serializers/infer.rs index 45d8957bb..514a6711b 100644 --- a/src/serializers/infer.rs +++ b/src/serializers/infer.rs @@ -266,7 +266,7 @@ pub(crate) fn infer_to_python_known( ObType::Generator => { let iter = super::type_serializers::generator::SerializationIterator::new( value.downcast()?, - super::type_serializers::any::AnySerializer.into(), + super::type_serializers::any::AnySerializer::get(), SchemaFilter::default(), include, exclude, diff --git a/src/serializers/shared.rs b/src/serializers/shared.rs index b9e0a727d..e7930512c 100644 --- a/src/serializers/shared.rs +++ b/src/serializers/shared.rs @@ -40,7 +40,7 @@ macro_rules! combined_serializer { find_only: {$($builder:path;)*} both: {$($b_key:ident: $b_serializer:path;)*} ) => { - #[derive(Debug, Clone)] + #[derive(Debug)] #[enum_dispatch] pub enum CombinedSerializer { $($e_key($e_serializer),)* @@ -256,7 +256,7 @@ impl PyGcTraverse for CombinedSerializer { } #[enum_dispatch(CombinedSerializer)] -pub(crate) trait TypeSerializer: Send + Sync + Clone + Debug { +pub(crate) trait TypeSerializer: Send + Sync + Debug { fn to_python( &self, value: &Bound<'_, PyAny>, diff --git a/src/serializers/type_serializers/any.rs b/src/serializers/type_serializers/any.rs index 179e2885d..3056959ea 100644 --- a/src/serializers/type_serializers/any.rs +++ b/src/serializers/type_serializers/any.rs @@ -1,4 +1,7 @@ -use std::borrow::Cow; +use std::{ + borrow::Cow, + sync::{Arc, OnceLock}, +}; use pyo3::prelude::*; use pyo3::types::PyDict; @@ -14,6 +17,13 @@ use super::{ #[derive(Debug, Clone, Default)] pub struct AnySerializer; +impl AnySerializer { + pub fn get() -> &'static Arc { + static ANY_SERIALIZER: OnceLock> = OnceLock::new(); + ANY_SERIALIZER.get_or_init(|| Arc::new(Self.into())) + } +} + impl BuildSerializer for AnySerializer { const EXPECTED_TYPE: &'static str = "any"; diff --git a/src/serializers/type_serializers/bytes.rs b/src/serializers/type_serializers/bytes.rs index 4fc53e224..fa17b941a 100644 --- a/src/serializers/type_serializers/bytes.rs +++ b/src/serializers/type_serializers/bytes.rs @@ -11,7 +11,7 @@ use super::{ TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct BytesSerializer { bytes_mode: BytesMode, } diff --git a/src/serializers/type_serializers/dataclass.rs b/src/serializers/type_serializers/dataclass.rs index ebcca0dec..ffe71adb9 100644 --- a/src/serializers/type_serializers/dataclass.rs +++ b/src/serializers/type_serializers/dataclass.rs @@ -61,7 +61,7 @@ impl BuildSerializer for DataclassArgsBuilder { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct DataclassSerializer { class: Py, serializer: Box, diff --git a/src/serializers/type_serializers/datetime_etc.rs b/src/serializers/type_serializers/datetime_etc.rs index a042ae99b..957fbcf29 100644 --- a/src/serializers/type_serializers/datetime_etc.rs +++ b/src/serializers/type_serializers/datetime_etc.rs @@ -38,7 +38,7 @@ fn downcast_date_reject_datetime<'a, 'py>(py_date: &'a Bound<'py, PyAny>) -> PyR macro_rules! build_serializer { ($struct_name:ident, $expected_type:literal, $downcast:path, $convert_func:ident $(, $json_check_func:ident)?) => { - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name; impl BuildSerializer for $struct_name { diff --git a/src/serializers/type_serializers/decimal.rs b/src/serializers/type_serializers/decimal.rs index 6237f53cb..2da84ab8f 100644 --- a/src/serializers/type_serializers/decimal.rs +++ b/src/serializers/type_serializers/decimal.rs @@ -11,7 +11,7 @@ use super::{ infer_json_key, infer_serialize, infer_to_python, BuildSerializer, CombinedSerializer, Extra, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct DecimalSerializer {} impl BuildSerializer for DecimalSerializer { diff --git a/src/serializers/type_serializers/definitions.rs b/src/serializers/type_serializers/definitions.rs index 071e50f8c..38fd7cea5 100644 --- a/src/serializers/type_serializers/definitions.rs +++ b/src/serializers/type_serializers/definitions.rs @@ -12,7 +12,7 @@ use crate::tools::SchemaDict; use super::{py_err_se_err, BuildSerializer, CombinedSerializer, Extra, TypeSerializer}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct DefinitionsSerializerBuilder; impl BuildSerializer for DefinitionsSerializerBuilder { diff --git a/src/serializers/type_serializers/dict.rs b/src/serializers/type_serializers/dict.rs index cf4458bd7..ec750faed 100644 --- a/src/serializers/type_serializers/dict.rs +++ b/src/serializers/type_serializers/dict.rs @@ -15,7 +15,7 @@ use super::{ SchemaFilter, SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct DictSerializer { key_serializer: Box, value_serializer: Box, diff --git a/src/serializers/type_serializers/enum_.rs b/src/serializers/type_serializers/enum_.rs index d4d8aec02..8a604e772 100644 --- a/src/serializers/type_serializers/enum_.rs +++ b/src/serializers/type_serializers/enum_.rs @@ -15,7 +15,7 @@ use super::simple::IntSerializer; use super::string::StrSerializer; use super::{BuildSerializer, CombinedSerializer, Extra, TypeSerializer}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct EnumSerializer { class: Py, serializer: Option>, diff --git a/src/serializers/type_serializers/float.rs b/src/serializers/type_serializers/float.rs index 13af9294c..8ade81157 100644 --- a/src/serializers/type_serializers/float.rs +++ b/src/serializers/type_serializers/float.rs @@ -15,7 +15,7 @@ use super::{ SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FloatSerializer { inf_nan_mode: InfNanMode, } diff --git a/src/serializers/type_serializers/format.rs b/src/serializers/type_serializers/format.rs index 8b180f505..cf785c1cc 100644 --- a/src/serializers/type_serializers/format.rs +++ b/src/serializers/type_serializers/format.rs @@ -53,7 +53,7 @@ impl WhenUsed { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FormatSerializer { format_func: PyObject, formatting_string: Py, @@ -161,7 +161,7 @@ impl TypeSerializer for FormatSerializer { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ToStringSerializer { when_used: WhenUsed, } diff --git a/src/serializers/type_serializers/function.rs b/src/serializers/type_serializers/function.rs index 856be6fb3..d0fea665f 100644 --- a/src/serializers/type_serializers/function.rs +++ b/src/serializers/type_serializers/function.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::sync::Arc; use pyo3::exceptions::{PyAttributeError, PyRecursionError, PyRuntimeError}; use pyo3::gc::PyVisit; @@ -71,7 +72,7 @@ impl BuildSerializer for FunctionPlainSerializerBuilder { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FunctionPlainSerializer { func: PyObject, name: String, @@ -314,13 +315,13 @@ impl BuildSerializer for FunctionWrapSerializerBuilder { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct FunctionWrapSerializer { - serializer: Box, + serializer: Arc, func: PyObject, name: String, function_name: String, - return_serializer: Box, + return_serializer: Arc, when_used: WhenUsed, is_field_serializer: bool, info_arg: bool, @@ -358,11 +359,11 @@ impl BuildSerializer for FunctionWrapSerializer { let name = format!("wrap_function[{function_name}, {}]", serializer.get_name()); Ok(Self { - serializer: Box::new(serializer), + serializer: Arc::new(serializer), func: function.into_py(py), function_name, name, - return_serializer: Box::new(return_serializer), + return_serializer: Arc::new(return_serializer), when_used: WhenUsed::new(&ser_schema, WhenUsed::Always)?, is_field_serializer, info_arg, @@ -419,10 +420,9 @@ impl_py_gc_traverse!(FunctionWrapSerializer { function_type_serializer!(FunctionWrapSerializer); #[pyclass(module = "pydantic_core._pydantic_core")] -#[derive(Clone)] #[cfg_attr(debug_assertions, derive(Debug))] pub(crate) struct SerializationCallable { - serializer: CombinedSerializer, + serializer: Arc, extra_owned: ExtraOwned, filter: AnyFilter, include: Option, @@ -432,7 +432,7 @@ pub(crate) struct SerializationCallable { impl SerializationCallable { pub fn new( py: Python, - serializer: &CombinedSerializer, + serializer: &Arc, include: Option<&Bound<'_, PyAny>>, exclude: Option<&Bound<'_, PyAny>>, extra: &Extra, diff --git a/src/serializers/type_serializers/generator.rs b/src/serializers/type_serializers/generator.rs index d7d211456..c85cd0f72 100644 --- a/src/serializers/type_serializers/generator.rs +++ b/src/serializers/type_serializers/generator.rs @@ -1,4 +1,5 @@ use std::borrow::Cow; +use std::sync::Arc; use pyo3::gc::PyVisit; use pyo3::intern; @@ -17,9 +18,9 @@ use super::{ PydanticSerializer, SchemaFilter, SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct GeneratorSerializer { - item_serializer: Box, + item_serializer: Arc, filter: SchemaFilter, } @@ -37,7 +38,7 @@ impl BuildSerializer for GeneratorSerializer { None => AnySerializer::build(schema, config, definitions)?, }; Ok(Self { - item_serializer: Box::new(item_serializer), + item_serializer: Arc::new(item_serializer), filter: SchemaFilter::from_schema(schema)?, } .into()) @@ -82,7 +83,7 @@ impl TypeSerializer for GeneratorSerializer { _ => { let iter = SerializationIterator::new( py_iter, - self.item_serializer.as_ref().clone(), + &self.item_serializer, self.filter.clone(), include, exclude, @@ -152,13 +153,12 @@ impl TypeSerializer for GeneratorSerializer { } #[pyclass(module = "pydantic_core._pydantic_core")] -#[derive(Clone)] #[cfg_attr(debug_assertions, derive(Debug))] pub(crate) struct SerializationIterator { iterator: Py, #[pyo3(get)] index: usize, - item_serializer: CombinedSerializer, + item_serializer: Arc, extra_owned: ExtraOwned, filter: SchemaFilter, include: Option, @@ -168,7 +168,7 @@ pub(crate) struct SerializationIterator { impl SerializationIterator { pub fn new( py_iter: &Bound<'_, PyIterator>, - item_serializer: CombinedSerializer, + item_serializer: &Arc, filter: SchemaFilter, include: Option<&Bound<'_, PyAny>>, exclude: Option<&Bound<'_, PyAny>>, @@ -177,7 +177,7 @@ impl SerializationIterator { Self { iterator: py_iter.clone().into(), index: 0, - item_serializer, + item_serializer: item_serializer.clone(), extra_owned: ExtraOwned::new(extra), filter, include: include.map(|v| v.clone().into()), diff --git a/src/serializers/type_serializers/json.rs b/src/serializers/type_serializers/json.rs index 8bc87bb2c..7f9b20492 100644 --- a/src/serializers/type_serializers/json.rs +++ b/src/serializers/type_serializers/json.rs @@ -16,7 +16,7 @@ use super::{ TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct JsonSerializer { serializer: Box, } diff --git a/src/serializers/type_serializers/json_or_python.rs b/src/serializers/type_serializers/json_or_python.rs index ce9a9c8c9..0e2de3370 100644 --- a/src/serializers/type_serializers/json_or_python.rs +++ b/src/serializers/type_serializers/json_or_python.rs @@ -8,7 +8,7 @@ use super::{BuildSerializer, CombinedSerializer, Extra, TypeSerializer}; use crate::definitions::DefinitionsBuilder; use crate::tools::SchemaDict; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct JsonOrPythonSerializer { json: Box, python: Box, diff --git a/src/serializers/type_serializers/list.rs b/src/serializers/type_serializers/list.rs index 44805f523..adec6c13c 100644 --- a/src/serializers/type_serializers/list.rs +++ b/src/serializers/type_serializers/list.rs @@ -15,7 +15,7 @@ use super::{ SchemaFilter, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ListSerializer { item_serializer: Box, filter: SchemaFilter, diff --git a/src/serializers/type_serializers/literal.rs b/src/serializers/type_serializers/literal.rs index 258f35ed9..ce353dc03 100644 --- a/src/serializers/type_serializers/literal.rs +++ b/src/serializers/type_serializers/literal.rs @@ -16,7 +16,7 @@ use super::{ SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct LiteralSerializer { expected_int: AHashSet, expected_str: AHashSet, diff --git a/src/serializers/type_serializers/model.rs b/src/serializers/type_serializers/model.rs index 5459c63ac..8df3f9678 100644 --- a/src/serializers/type_serializers/model.rs +++ b/src/serializers/type_serializers/model.rs @@ -72,7 +72,7 @@ impl BuildSerializer for ModelFieldsBuilder { } } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct ModelSerializer { class: Py, serializer: Box, diff --git a/src/serializers/type_serializers/nullable.rs b/src/serializers/type_serializers/nullable.rs index 4abd56808..fb63384d1 100644 --- a/src/serializers/type_serializers/nullable.rs +++ b/src/serializers/type_serializers/nullable.rs @@ -9,7 +9,7 @@ use crate::tools::SchemaDict; use super::{infer_json_key_known, BuildSerializer, CombinedSerializer, Extra, IsType, ObType, TypeSerializer}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct NullableSerializer { serializer: Box, } diff --git a/src/serializers/type_serializers/set_frozenset.rs b/src/serializers/type_serializers/set_frozenset.rs index 5e3d5ae29..7373c286d 100644 --- a/src/serializers/type_serializers/set_frozenset.rs +++ b/src/serializers/type_serializers/set_frozenset.rs @@ -17,7 +17,7 @@ use super::{ macro_rules! build_serializer { ($struct_name:ident, $expected_type:literal, $py_type:ty) => { - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name { item_serializer: Box, name: String, diff --git a/src/serializers/type_serializers/simple.rs b/src/serializers/type_serializers/simple.rs index 5ad315a31..5df8ec071 100644 --- a/src/serializers/type_serializers/simple.rs +++ b/src/serializers/type_serializers/simple.rs @@ -13,7 +13,7 @@ use super::{ SerCheck, SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct NoneSerializer; impl BuildSerializer for NoneSerializer { @@ -87,7 +87,7 @@ impl TypeSerializer for NoneSerializer { macro_rules! build_simple_serializer { ($struct_name:ident, $expected_type:literal, $rust_type:ty, $ob_type:expr, $key_method:ident, $subtypes_allowed:expr) => { - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name; impl $struct_name { diff --git a/src/serializers/type_serializers/string.rs b/src/serializers/type_serializers/string.rs index 33b7d0d12..9e9a7162e 100644 --- a/src/serializers/type_serializers/string.rs +++ b/src/serializers/type_serializers/string.rs @@ -10,7 +10,7 @@ use super::{ IsType, ObType, SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct StrSerializer; impl StrSerializer { diff --git a/src/serializers/type_serializers/timedelta.rs b/src/serializers/type_serializers/timedelta.rs index a28258e2a..a62b595d0 100644 --- a/src/serializers/type_serializers/timedelta.rs +++ b/src/serializers/type_serializers/timedelta.rs @@ -12,7 +12,7 @@ use super::{ TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct TimeDeltaSerializer { timedelta_mode: TimedeltaMode, } diff --git a/src/serializers/type_serializers/tuple.rs b/src/serializers/type_serializers/tuple.rs index 3dd5b1ca9..07196bf43 100644 --- a/src/serializers/type_serializers/tuple.rs +++ b/src/serializers/type_serializers/tuple.rs @@ -17,7 +17,7 @@ use super::{ PydanticSerializer, SchemaFilter, SerMode, TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct TupleSerializer { serializers: Vec, variadic_item_index: Option, diff --git a/src/serializers/type_serializers/typed_dict.rs b/src/serializers/type_serializers/typed_dict.rs index 90b448fb2..e80a9e9b3 100644 --- a/src/serializers/type_serializers/typed_dict.rs +++ b/src/serializers/type_serializers/typed_dict.rs @@ -11,7 +11,7 @@ use crate::tools::SchemaDict; use super::{BuildSerializer, CombinedSerializer, ComputedFields, FieldsMode, GeneralFieldsSerializer, SerField}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct TypedDictBuilder; impl BuildSerializer for TypedDictBuilder { diff --git a/src/serializers/type_serializers/union.rs b/src/serializers/type_serializers/union.rs index 4ca7fb06b..2915115c3 100644 --- a/src/serializers/type_serializers/union.rs +++ b/src/serializers/type_serializers/union.rs @@ -14,7 +14,7 @@ use super::{ TypeSerializer, }; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct UnionSerializer { choices: Vec, name: String, diff --git a/src/serializers/type_serializers/url.rs b/src/serializers/type_serializers/url.rs index f7dccf017..2ed2af739 100644 --- a/src/serializers/type_serializers/url.rs +++ b/src/serializers/type_serializers/url.rs @@ -14,7 +14,7 @@ use super::{ macro_rules! build_serializer { ($struct_name:ident, $expected_type:literal, $extract:ty) => { - #[derive(Debug, Clone)] + #[derive(Debug)] pub struct $struct_name; impl BuildSerializer for $struct_name { diff --git a/src/serializers/type_serializers/uuid.rs b/src/serializers/type_serializers/uuid.rs index 9609f11da..01627c27c 100644 --- a/src/serializers/type_serializers/uuid.rs +++ b/src/serializers/type_serializers/uuid.rs @@ -18,7 +18,7 @@ pub(crate) fn uuid_to_string(py_uuid: &Bound<'_, PyAny>) -> PyResult { Ok(uuid.to_string()) } -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct UuidSerializer; impl_py_gc_traverse!(UuidSerializer {}); diff --git a/src/serializers/type_serializers/with_default.rs b/src/serializers/type_serializers/with_default.rs index 0e50e10a2..6d510ce55 100644 --- a/src/serializers/type_serializers/with_default.rs +++ b/src/serializers/type_serializers/with_default.rs @@ -10,7 +10,7 @@ use crate::validators::DefaultType; use super::{BuildSerializer, CombinedSerializer, Extra, TypeSerializer}; -#[derive(Debug, Clone)] +#[derive(Debug)] pub struct WithDefaultSerializer { default: DefaultType, serializer: Box,