Skip to content

Commit

Permalink
SerializeState for fast call convention, repr(transparent)
Browse files Browse the repository at this point in the history
  • Loading branch information
ijl committed Nov 23, 2023
1 parent bdfcaa0 commit 558d08a
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 378 deletions.
2 changes: 1 addition & 1 deletion src/opt.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
103 changes: 27 additions & 76 deletions src/serialize/per_type/dataclass.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand All @@ -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<NonNull<pyo3_ffi::PyObject>>,
#[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<NonNull<pyo3_ffi::PyObject>>,
) -> 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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
}
Expand All @@ -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<NonNull<pyo3_ffi::PyObject>>,
}

impl DataclassFastSerializer {
pub fn new(
ptr: *mut pyo3_ffi::PyObject,
opts: Opt,
default_calls: u8,
recursion: u8,
state: SerializerState,
default: Option<NonNull<pyo3_ffi::PyObject>>,
) -> Self {
DataclassFastSerializer {
ptr: ptr,
opts: opts,
default_calls: default_calls,
recursion: recursion,
state: state.copy_for_recursive_call(),
default: default,
}
}
Expand Down Expand Up @@ -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)?;
}
Expand All @@ -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<NonNull<pyo3_ffi::PyObject>>,
}

impl DataclassFallbackSerializer {
pub fn new(
ptr: *mut pyo3_ffi::PyObject,
opts: Opt,
default_calls: u8,
recursion: u8,
state: SerializerState,
default: Option<NonNull<pyo3_ffi::PyObject>>,
) -> Self {
DataclassFallbackSerializer {
ptr: ptr,
opts: opts,
default_calls: default_calls,
recursion: recursion,
state: state.copy_for_recursive_call(),
default: default,
}
}
Expand Down Expand Up @@ -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)?
Expand Down
50 changes: 15 additions & 35 deletions src/serialize/per_type/default.rs
Original file line number Diff line number Diff line change
@@ -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<NonNull<pyo3_ffi::PyObject>>,
#[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<NonNull<pyo3_ffi::PyObject>>,
) -> 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<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
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))),
}
}
}
Loading

0 comments on commit 558d08a

Please sign in to comment.