From b66b5665a48e53bf4d6bef1bcbffbdc96673f209 Mon Sep 17 00:00:00 2001 From: ijl Date: Thu, 23 Nov 2023 16:50:04 +0000 Subject: [PATCH] SerializeState for fast call convention, repr(transparent) --- src/opt.rs | 2 +- src/serialize/per_type/dataclass.rs | 103 +++++------------ src/serialize/per_type/default.rs | 50 +++------ src/serialize/per_type/dict.rs | 114 +++++-------------- src/serialize/per_type/list.rs | 26 ++--- src/serialize/per_type/numpy.rs | 48 +++----- src/serialize/per_type/pyenum.rs | 43 ++------ src/serialize/per_type/tuple.rs | 24 +--- src/serialize/per_type/uuid.rs | 1 + src/serialize/serializer.rs | 164 +++++++++++++++------------- src/typeref.rs | 1 + 11 files changed, 198 insertions(+), 378 deletions(-) diff --git a/src/opt.rs b/src/opt.rs index 06963d62..4ceff66b 100644 --- a/src/opt.rs +++ b/src/opt.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -pub type Opt = u16; +pub type Opt = u32; pub const INDENT_2: Opt = 1; pub const NAIVE_UTC: Opt = 1 << 1; diff --git a/src/serialize/per_type/dataclass.rs b/src/serialize/per_type/dataclass.rs index 6541d398..d1a99003 100644 --- a/src/serialize/per_type/dataclass.rs +++ b/src/serialize/per_type/dataclass.rs @@ -1,6 +1,5 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -use crate::opt::*; use crate::serialize::error::*; use crate::serialize::serializer::*; use crate::str::*; @@ -10,73 +9,49 @@ use serde::ser::{Serialize, SerializeMap, Serializer}; use std::ptr::NonNull; -pub struct DataclassGenericSerializer { - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, +#[repr(transparent)] +pub struct DataclassGenericSerializer<'a> { + previous: &'a PyObjectSerializer, } -impl DataclassGenericSerializer { - pub fn new( - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, - ) -> Self { - DataclassGenericSerializer { - ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion + 1, - default: default, - } +impl<'a> DataclassGenericSerializer<'a> { + pub fn new(previous: &'a PyObjectSerializer) -> Self { + Self { previous: previous } } } -impl Serialize for DataclassGenericSerializer { +impl<'a> Serialize for DataclassGenericSerializer<'a> { #[inline(never)] fn serialize(&self, serializer: S) -> Result where S: Serializer, { - if unlikely!(self.recursion == RECURSION_LIMIT) { + if unlikely!(self.previous.state.recursion_limit()) { err!(SerializeError::RecursionLimit) } - let dict = ffi!(PyObject_GetAttr(self.ptr, DICT_STR)); - let ob_type = ob_type!(self.ptr); + let dict = ffi!(PyObject_GetAttr(self.previous.ptr, DICT_STR)); + let ob_type = ob_type!(self.previous.ptr); if unlikely!(dict.is_null()) { ffi!(PyErr_Clear()); DataclassFallbackSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, + self.previous.ptr, + self.previous.state, + self.previous.default, ) .serialize(serializer) } else if pydict_contains!(ob_type, SLOTS_STR) { let ret = DataclassFallbackSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, + self.previous.ptr, + self.previous.state, + self.previous.default, ) .serialize(serializer); ffi!(Py_DECREF(dict)); ret } else { - let ret = DataclassFastSerializer::new( - dict, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer); + let ret = + DataclassFastSerializer::new(dict, self.previous.state, self.previous.default) + .serialize(serializer); ffi!(Py_DECREF(dict)); ret } @@ -85,25 +60,19 @@ impl Serialize for DataclassGenericSerializer { pub struct DataclassFastSerializer { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl DataclassFastSerializer { pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { DataclassFastSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state.copy_for_recursive_call(), default: default, } } @@ -152,13 +121,7 @@ impl Serialize for DataclassFastSerializer { if unlikely!(key_as_str.as_bytes()[0] == b'_') { continue; } - let pyvalue = PyObjectSerializer::new( - value, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let pyvalue = PyObjectSerializer::new(value, self.state, self.default); map.serialize_key(key_as_str).unwrap(); map.serialize_value(&pyvalue)?; } @@ -168,25 +131,19 @@ impl Serialize for DataclassFastSerializer { pub struct DataclassFallbackSerializer { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl DataclassFallbackSerializer { pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { DataclassFallbackSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state.copy_for_recursive_call(), default: default, } } @@ -246,13 +203,7 @@ impl Serialize for DataclassFallbackSerializer { let value = ffi!(PyObject_GetAttr(self.ptr, attr)); debug_assert!(ffi!(Py_REFCNT(value)) >= 2); ffi!(Py_DECREF(value)); - let pyvalue = PyObjectSerializer::new( - value, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let pyvalue = PyObjectSerializer::new(value, self.state, self.default); map.serialize_key(key_as_str).unwrap(); map.serialize_value(&pyvalue)? diff --git a/src/serialize/per_type/default.rs b/src/serialize/per_type/default.rs index 6f2d0982..f6a1a872 100644 --- a/src/serialize/per_type/default.rs +++ b/src/serialize/per_type/default.rs @@ -1,82 +1,62 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -use crate::opt::*; use crate::serialize::error::*; use crate::serialize::serializer::*; use serde::ser::{Serialize, Serializer}; -use std::ptr::NonNull; - -pub struct DefaultSerializer { - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, +#[repr(transparent)] +pub struct DefaultSerializer<'a> { + previous: &'a PyObjectSerializer, } -impl DefaultSerializer { - pub fn new( - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, - ) -> Self { - DefaultSerializer { - ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, - default: default, - } +impl<'a> DefaultSerializer<'a> { + pub fn new(previous: &'a PyObjectSerializer) -> Self { + Self { previous: previous } } } -impl Serialize for DefaultSerializer { +impl<'a> Serialize for DefaultSerializer<'a> { #[inline(never)] #[cfg_attr(feature = "optimize", optimize(size))] fn serialize(&self, serializer: S) -> Result where S: Serializer, { - match self.default { + match self.previous.default { Some(callable) => { - if unlikely!(self.default_calls == RECURSION_LIMIT) { + if unlikely!(self.previous.state.default_calls_limit()) { err!(SerializeError::DefaultRecursionLimit) } #[cfg(not(Py_3_10))] let default_obj = ffi!(PyObject_CallFunctionObjArgs( callable.as_ptr(), - self.ptr, + self.previous.ptr, std::ptr::null_mut() as *mut pyo3_ffi::PyObject )); #[cfg(Py_3_10)] let default_obj = unsafe { pyo3_ffi::PyObject_Vectorcall( callable.as_ptr(), - std::ptr::addr_of!(self.ptr), + std::ptr::addr_of!(self.previous.ptr), pyo3_ffi::PyVectorcall_NARGS(1) as usize, std::ptr::null_mut(), ) }; if unlikely!(default_obj.is_null()) { - err!(SerializeError::UnsupportedType(nonnull!(self.ptr))) + err!(SerializeError::UnsupportedType(nonnull!(self.previous.ptr))) } else { let res = PyObjectSerializer::new( default_obj, - self.opts, - self.default_calls + 1, - self.recursion, - self.default, + self.previous.state.copy_for_default_call(), + self.previous.default, ) .serialize(serializer); ffi!(Py_DECREF(default_obj)); res } } - None => err!(SerializeError::UnsupportedType(nonnull!(self.ptr))), + None => err!(SerializeError::UnsupportedType(nonnull!(self.previous.ptr))), } } } diff --git a/src/serialize/per_type/dict.rs b/src/serialize/per_type/dict.rs index a20eaf06..99357119 100644 --- a/src/serialize/per_type/dict.rs +++ b/src/serialize/per_type/dict.rs @@ -5,7 +5,7 @@ use crate::serialize::error::*; use crate::serialize::per_type::datetimelike::{DateTimeBuffer, DateTimeLike}; use crate::serialize::per_type::*; use crate::serialize::serializer::{ - pyobject_to_obtype, ObType, PyObjectSerializer, RECURSION_LIMIT, + pyobject_to_obtype, ObType, PyObjectSerializer, SerializerState, }; use crate::str::*; use crate::typeref::*; @@ -16,25 +16,20 @@ use std::ptr::NonNull; pub struct DictGenericSerializer { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl DictGenericSerializer { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { DictGenericSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion + 1, + state: state.copy_for_recursive_call(), default: default, } } @@ -46,62 +41,36 @@ impl Serialize for DictGenericSerializer { where S: Serializer, { - if unlikely!(self.recursion == RECURSION_LIMIT) { + if unlikely!(self.state.recursion_limit()) { err!(SerializeError::RecursionLimit) } if unlikely!(ffi!(Py_SIZE(self.ptr)) == 0) { serializer.serialize_map(Some(0)).unwrap().end() - } else if opt_disabled!(self.opts, SORT_OR_NON_STR_KEYS) { - Dict::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer) - } else if opt_enabled!(self.opts, NON_STR_KEYS) { - DictNonStrKey::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer) + } else if opt_disabled!(self.state.opts(), SORT_OR_NON_STR_KEYS) { + Dict::new(self.ptr, self.state, self.default).serialize(serializer) + } else if opt_enabled!(self.state.opts(), NON_STR_KEYS) { + DictNonStrKey::new(self.ptr, self.state, self.default).serialize(serializer) } else { - DictSortedKey::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer) + DictSortedKey::new(self.ptr, self.state, self.default).serialize(serializer) } } } pub struct Dict { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl Dict { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { Dict { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state, default: default, } } @@ -143,13 +112,7 @@ impl Serialize for Dict { if unlikely!(key_as_str.is_none()) { err!(SerializeError::InvalidStr) } - let pyvalue = PyObjectSerializer::new( - value, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let pyvalue = PyObjectSerializer::new(value, self.state, self.default); map.serialize_key(key_as_str.unwrap()).unwrap(); map.serialize_value(&pyvalue)?; } @@ -159,25 +122,20 @@ impl Serialize for Dict { pub struct DictSortedKey { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl DictSortedKey { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { DictSortedKey { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state, default: default, } } @@ -229,13 +187,7 @@ impl Serialize for DictSortedKey { let mut map = serializer.serialize_map(None).unwrap(); for (key, val) in items.iter() { - let pyvalue = PyObjectSerializer::new( - *val, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let pyvalue = PyObjectSerializer::new(*val, self.state, self.default); map.serialize_key(key).unwrap(); map.serialize_value(&pyvalue)?; } @@ -245,25 +197,20 @@ impl Serialize for DictSortedKey { pub struct DictNonStrKey { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl DictNonStrKey { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { DictNonStrKey { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state, default: default, } } @@ -379,7 +326,8 @@ impl Serialize for DictNonStrKey { let len = ffi!(Py_SIZE(self.ptr)) as usize; let mut items: SmallVec<[(CompactString, *mut pyo3_ffi::PyObject); 8]> = SmallVec::with_capacity(len); - let opts = self.opts & NOT_PASSTHROUGH; + + let opts = self.state.opts() & NOT_PASSTHROUGH; let mut next_key: *mut pyo3_ffi::PyObject = std::ptr::null_mut(); let mut next_value: *mut pyo3_ffi::PyObject = std::ptr::null_mut(); @@ -423,13 +371,7 @@ impl Serialize for DictNonStrKey { let mut map = serializer.serialize_map(None).unwrap(); for (key, val) in items.iter() { - let pyvalue = PyObjectSerializer::new( - *val, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let pyvalue = PyObjectSerializer::new(*val, self.state, self.default); map.serialize_key(key).unwrap(); map.serialize_value(&pyvalue)?; } diff --git a/src/serialize/per_type/list.rs b/src/serialize/per_type/list.rs index 9e51bfa9..8f0856c8 100644 --- a/src/serialize/per_type/list.rs +++ b/src/serialize/per_type/list.rs @@ -1,34 +1,28 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) use crate::ffi::PyListIter; -use crate::opt::*; use crate::serialize::error::*; -use crate::serialize::serializer::{PyObjectSerializer, RECURSION_LIMIT}; +use crate::serialize::serializer::{PyObjectSerializer, SerializerState}; use serde::ser::{Serialize, SerializeSeq, Serializer}; use std::ptr::NonNull; pub struct ListSerializer { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl ListSerializer { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { ListSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion + 1, + state: state.copy_for_recursive_call(), default: default, } } @@ -39,7 +33,7 @@ impl Serialize for ListSerializer { where S: Serializer, { - if unlikely!(self.recursion == RECURSION_LIMIT) { + if unlikely!(self.state.recursion_limit()) { err!(SerializeError::RecursionLimit) } if ffi!(Py_SIZE(self.ptr)) == 0 { @@ -47,13 +41,7 @@ impl Serialize for ListSerializer { } else { let mut seq = serializer.serialize_seq(None).unwrap(); for elem in PyListIter::from_pyobject(self.ptr) { - let value = PyObjectSerializer::new( - elem.as_ptr(), - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let value = PyObjectSerializer::new(elem.as_ptr(), self.state, self.default); seq.serialize_element(&value)?; } seq.end() diff --git a/src/serialize/per_type/numpy.rs b/src/serialize/per_type/numpy.rs index 0bfd60eb..715648e2 100644 --- a/src/serialize/per_type/numpy.rs +++ b/src/serialize/per_type/numpy.rs @@ -5,6 +5,7 @@ use crate::serialize::per_type::datetimelike::{ DateTimeBuffer, DateTimeError, DateTimeLike, Offset, }; use crate::serialize::per_type::*; +use crate::serialize::serializer::PyObjectSerializer; use crate::typeref::{load_numpy_types, ARRAY_STRUCT_STR, DESCR_STR, DTYPE_STR, NUMPY_TYPES}; use chrono::{Datelike, NaiveDate, NaiveDateTime, Timelike}; use pyo3_ffi::*; @@ -12,35 +13,19 @@ use serde::ser::{self, Serialize, SerializeSeq, Serializer}; use std::convert::TryInto; use std::fmt; use std::os::raw::{c_char, c_int, c_void}; -use std::ptr::NonNull; -pub struct NumpySerializer { - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, -} - -impl NumpySerializer { - pub fn new( - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, - ) -> Self { - NumpySerializer { - ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, - default: default, - } +#[repr(transparent)] +pub struct NumpySerializer<'a> { + previous: &'a PyObjectSerializer, +} + +impl<'a> NumpySerializer<'a> { + pub fn new(previous: &'a PyObjectSerializer) -> Self { + Self { previous: previous } } } -impl Serialize for NumpySerializer { +impl<'a> Serialize for NumpySerializer<'a> { #[cold] #[inline(never)] #[cfg_attr(feature = "optimize", optimize(size))] @@ -48,20 +33,13 @@ impl Serialize for NumpySerializer { where S: Serializer, { - match NumpyArray::new(self.ptr, self.opts) { + match NumpyArray::new(self.previous.ptr, self.previous.state.opts()) { Ok(val) => val.serialize(serializer), Err(PyArrayError::Malformed) => err!(SerializeError::NumpyMalformed), Err(PyArrayError::NotContiguous) | Err(PyArrayError::UnsupportedDataType) - if self.default.is_some() => + if self.previous.default.is_some() => { - DefaultSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer) + DefaultSerializer::new(self.previous).serialize(serializer) } Err(PyArrayError::NotContiguous) => { err!(SerializeError::NumpyNotCContiguous) diff --git a/src/serialize/per_type/pyenum.rs b/src/serialize/per_type/pyenum.rs index 1972f8a2..eedc54cd 100644 --- a/src/serialize/per_type/pyenum.rs +++ b/src/serialize/per_type/pyenum.rs @@ -1,53 +1,30 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -use crate::opt::*; use crate::serialize::serializer::*; use crate::typeref::*; use serde::ser::{Serialize, Serializer}; -use std::ptr::NonNull; -pub struct EnumSerializer { - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, +#[repr(transparent)] +pub struct EnumSerializer<'a> { + previous: &'a PyObjectSerializer, } -impl EnumSerializer { - pub fn new( - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, - ) -> Self { - EnumSerializer { - ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, - default: default, - } +impl<'a> EnumSerializer<'a> { + pub fn new(previous: &'a PyObjectSerializer) -> Self { + Self { previous: previous } } } -impl Serialize for EnumSerializer { +impl<'a> Serialize for EnumSerializer<'a> { #[inline(never)] fn serialize(&self, serializer: S) -> Result where S: Serializer, { - let value = ffi!(PyObject_GetAttr(self.ptr, VALUE_STR)); + let value = ffi!(PyObject_GetAttr(self.previous.ptr, VALUE_STR)); debug_assert!(ffi!(Py_REFCNT(value)) >= 2); - let ret = PyObjectSerializer::new( - value, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer); + let ret = PyObjectSerializer::new(value, self.previous.state, self.previous.default) + .serialize(serializer); ffi!(Py_DECREF(value)); ret } diff --git a/src/serialize/per_type/tuple.rs b/src/serialize/per_type/tuple.rs index 7ad76e42..ad937ae3 100644 --- a/src/serialize/per_type/tuple.rs +++ b/src/serialize/per_type/tuple.rs @@ -1,32 +1,26 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) -use crate::opt::*; -use crate::serialize::serializer::*; +use crate::serialize::serializer::{PyObjectSerializer, SerializerState}; use serde::ser::{Serialize, SerializeSeq, Serializer}; use std::ptr::NonNull; pub struct TupleSerializer { ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, } impl TupleSerializer { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { TupleSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion + 1, + state: state.copy_for_recursive_call(), default: default, } } @@ -44,13 +38,7 @@ impl Serialize for TupleSerializer { let mut seq = serializer.serialize_seq(None).unwrap(); for i in 0..=ffi!(Py_SIZE(self.ptr)) as usize - 1 { let elem = ffi!(PyTuple_GET_ITEM(self.ptr, i as isize)); - let value = PyObjectSerializer::new( - elem, - self.opts, - self.default_calls, - self.recursion, - self.default, - ); + let value = PyObjectSerializer::new(elem, self.state, self.default); seq.serialize_element(&value)?; } seq.end() diff --git a/src/serialize/per_type/uuid.rs b/src/serialize/per_type/uuid.rs index e4079475..ddaa2df2 100644 --- a/src/serialize/per_type/uuid.rs +++ b/src/serialize/per_type/uuid.rs @@ -7,6 +7,7 @@ use std::os::raw::c_uchar; pub type UUIDBuffer = arrayvec::ArrayVec; +#[repr(transparent)] pub struct UUID { ptr: *mut pyo3_ffi::PyObject, } diff --git a/src/serialize/serializer.rs b/src/serialize/serializer.rs index 24f0464e..139a1d4c 100644 --- a/src/serialize/serializer.rs +++ b/src/serialize/serializer.rs @@ -10,15 +10,13 @@ use std::ptr::NonNull; use crate::serialize::json::{to_writer, to_writer_pretty}; -pub const RECURSION_LIMIT: u8 = 255; - pub fn serialize( ptr: *mut pyo3_ffi::PyObject, default: Option>, opts: Opt, ) -> Result, String> { let mut buf = BytesWriter::default(); - let obj = PyObjectSerializer::new(ptr, opts, 0, 0, default); + let obj = PyObjectSerializer::new(ptr, SerializerState::new(opts), default); let res = if opt_disabled!(opts, INDENT_2) { to_writer(&mut buf, &obj) } else { @@ -136,27 +134,84 @@ pub fn pyobject_to_obtype_unlikely(ob_type: *mut pyo3_ffi::PyTypeObject, opts: O ObType::Unknown } +#[cfg(target_endian = "little")] +const RECURSION_MASK: u32 = 0b11111111_00000000_00000000_00000000; + +#[cfg(target_endian = "little")] +const DEFAULT_MASK: u32 = 0b00000000_11111111_00000000_00000000; + +#[cfg(target_endian = "big")] +const RECURSION_MASK: u32 = 0b00000000_00000000_00000000_11111111; + +#[cfg(target_endian = "big")] +const DEFAULT_MASK: u32 = 0b00000000_00000000_11111111_00000000; + +#[repr(transparent)] +#[derive(Copy, Clone)] +pub struct SerializerState { + // recursion: u8, + // default_calls: u8, + // opts: Opt, + state: u32, +} + +impl SerializerState { + #[inline(always)] + pub fn new(opts: Opt) -> Self { + debug_assert!(opts < u16::MAX as u32); + Self { state: opts } + } + + #[inline(always)] + pub fn opts(&self) -> u32 { + self.state + } + + #[inline(always)] + pub fn recursion_limit(&self) -> bool { + self.state & RECURSION_MASK == RECURSION_MASK + } + + #[inline(always)] + pub fn default_calls_limit(&self) -> bool { + self.state & DEFAULT_MASK == DEFAULT_MASK + } + + #[inline(always)] + pub fn copy_for_recursive_call(&self) -> Self { + let opt = self.state & !RECURSION_MASK; + let recursion = ((self.state >> 24) + 1) << 24; + Self { + state: opt | recursion, + } + } + + #[inline(always)] + pub fn copy_for_default_call(&self) -> Self { + let opt = self.state & !DEFAULT_MASK; + let default_calls = (((self.state << 8) >> 24) + 1) << 16; + Self { + state: opt | default_calls, + } + } +} + pub struct PyObjectSerializer { - ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, - default: Option>, + pub ptr: *mut pyo3_ffi::PyObject, + pub state: SerializerState, + pub default: Option>, } impl PyObjectSerializer { + #[inline(always)] pub fn new( ptr: *mut pyo3_ffi::PyObject, - opts: Opt, - default_calls: u8, - recursion: u8, + state: SerializerState, default: Option>, ) -> Self { PyObjectSerializer { ptr: ptr, - opts: opts, - default_calls: default_calls, - recursion: recursion, + state: state, default: default, } } @@ -167,11 +222,11 @@ impl Serialize for PyObjectSerializer { where S: Serializer, { - match pyobject_to_obtype(self.ptr, self.opts) { + match pyobject_to_obtype(self.ptr, self.state.opts()) { ObType::Str => StrSerializer::new(self.ptr).serialize(serializer), ObType::StrSubclass => StrSubclassSerializer::new(self.ptr).serialize(serializer), ObType::Int => { - if unlikely!(opt_enabled!(self.opts, STRICT_INTEGER)) { + if unlikely!(opt_enabled!(self.state.opts(), STRICT_INTEGER)) { Int53Serializer::new(self.ptr).serialize(serializer) } else { IntSerializer::new(self.ptr).serialize(serializer) @@ -180,68 +235,27 @@ impl Serialize for PyObjectSerializer { ObType::None => NoneSerializer::new().serialize(serializer), ObType::Float => FloatSerializer::new(self.ptr).serialize(serializer), ObType::Bool => BoolSerializer::new(self.ptr).serialize(serializer), - ObType::Datetime => DateTime::new(self.ptr, self.opts).serialize(serializer), + ObType::Datetime => DateTime::new(self.ptr, self.state.opts()).serialize(serializer), ObType::Date => Date::new(self.ptr).serialize(serializer), - ObType::Time => Time::new(self.ptr, self.opts).serialize(serializer), + ObType::Time => Time::new(self.ptr, self.state.opts()).serialize(serializer), ObType::Uuid => UUID::new(self.ptr).serialize(serializer), - ObType::Dict => DictGenericSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::List => ListSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::Tuple => TupleSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::Dataclass => DataclassGenericSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::Enum => EnumSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::NumpyArray => NumpySerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), - ObType::NumpyScalar => NumpyScalar::new(self.ptr, self.opts).serialize(serializer), + ObType::Dict => { + DictGenericSerializer::new(self.ptr, self.state, self.default).serialize(serializer) + } + ObType::List => { + ListSerializer::new(self.ptr, self.state, self.default).serialize(serializer) + } + ObType::Tuple => { + TupleSerializer::new(self.ptr, self.state, self.default).serialize(serializer) + } + ObType::Dataclass => DataclassGenericSerializer::new(self).serialize(serializer), + ObType::Enum => EnumSerializer::new(self).serialize(serializer), + ObType::NumpyArray => NumpySerializer::new(self).serialize(serializer), + ObType::NumpyScalar => { + NumpyScalar::new(self.ptr, self.state.opts()).serialize(serializer) + } ObType::Fragment => FragmentSerializer::new(self.ptr).serialize(serializer), - ObType::Unknown => DefaultSerializer::new( - self.ptr, - self.opts, - self.default_calls, - self.recursion, - self.default, - ) - .serialize(serializer), + ObType::Unknown => DefaultSerializer::new(self).serialize(serializer), } } } diff --git a/src/typeref.rs b/src/typeref.rs index 242a8275..ec096492 100644 --- a/src/typeref.rs +++ b/src/typeref.rs @@ -148,6 +148,7 @@ pub fn init_typerefs() { #[cfg_attr(feature = "optimize", optimize(size))] fn _init_typerefs_impl() -> bool { unsafe { + debug_assert!(crate::opt::MAX_OPT < u16::MAX as i32); assert!(crate::deserialize::KEY_MAP .set(crate::deserialize::KeyMap::default()) .is_ok());