Skip to content

Commit a40f58b

Browse files
committed
Simplify with SerializerState
1 parent 5205258 commit a40f58b

File tree

15 files changed

+327
-494
lines changed

15 files changed

+327
-494
lines changed

src/opt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
22

3-
pub type Opt = u16;
3+
pub type Opt = u32;
44

55
pub const INDENT_2: Opt = 1;
66
pub const NAIVE_UTC: Opt = 1 << 1;

src/serialize/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
22

33
mod error;
4+
mod obtype;
45
mod per_type;
56
mod serializer;
7+
mod state;
68
mod writer;
79

810
pub use serializer::serialize;

src/serialize/obtype.rs

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2+
3+
use crate::opt::{
4+
Opt, PASSTHROUGH_DATACLASS, PASSTHROUGH_DATETIME, PASSTHROUGH_SUBCLASS, SERIALIZE_NUMPY,
5+
};
6+
use crate::serialize::per_type::{is_numpy_array, is_numpy_scalar};
7+
use crate::typeref::{
8+
BOOL_TYPE, DATACLASS_FIELDS_STR, DATETIME_TYPE, DATE_TYPE, DICT_TYPE, ENUM_TYPE, FLOAT_TYPE,
9+
FRAGMENT_TYPE, INT_TYPE, LIST_TYPE, NONE_TYPE, STR_TYPE, TIME_TYPE, TUPLE_TYPE, UUID_TYPE,
10+
};
11+
12+
#[repr(u32)]
13+
pub enum ObType {
14+
Str,
15+
Int,
16+
Bool,
17+
None,
18+
Float,
19+
List,
20+
Dict,
21+
Datetime,
22+
Date,
23+
Time,
24+
Tuple,
25+
Uuid,
26+
Dataclass,
27+
NumpyScalar,
28+
NumpyArray,
29+
Enum,
30+
StrSubclass,
31+
Fragment,
32+
Unknown,
33+
}
34+
35+
pub fn pyobject_to_obtype(obj: *mut pyo3_ffi::PyObject, opts: Opt) -> ObType {
36+
let ob_type = ob_type!(obj);
37+
if is_class_by_type!(ob_type, STR_TYPE) {
38+
ObType::Str
39+
} else if is_class_by_type!(ob_type, INT_TYPE) {
40+
ObType::Int
41+
} else if is_class_by_type!(ob_type, BOOL_TYPE) {
42+
ObType::Bool
43+
} else if is_class_by_type!(ob_type, NONE_TYPE) {
44+
ObType::None
45+
} else if is_class_by_type!(ob_type, FLOAT_TYPE) {
46+
ObType::Float
47+
} else if is_class_by_type!(ob_type, LIST_TYPE) {
48+
ObType::List
49+
} else if is_class_by_type!(ob_type, DICT_TYPE) {
50+
ObType::Dict
51+
} else if is_class_by_type!(ob_type, DATETIME_TYPE) && opt_disabled!(opts, PASSTHROUGH_DATETIME)
52+
{
53+
ObType::Datetime
54+
} else {
55+
pyobject_to_obtype_unlikely(ob_type, opts)
56+
}
57+
}
58+
59+
#[cfg_attr(feature = "optimize", optimize(size))]
60+
#[inline(never)]
61+
pub fn pyobject_to_obtype_unlikely(ob_type: *mut pyo3_ffi::PyTypeObject, opts: Opt) -> ObType {
62+
if is_class_by_type!(ob_type, UUID_TYPE) {
63+
return ObType::Uuid;
64+
} else if is_class_by_type!(ob_type, TUPLE_TYPE) {
65+
return ObType::Tuple;
66+
} else if is_class_by_type!(ob_type, FRAGMENT_TYPE) {
67+
return ObType::Fragment;
68+
}
69+
70+
if opt_disabled!(opts, PASSTHROUGH_DATETIME) {
71+
if is_class_by_type!(ob_type, DATE_TYPE) {
72+
return ObType::Date;
73+
} else if is_class_by_type!(ob_type, TIME_TYPE) {
74+
return ObType::Time;
75+
}
76+
}
77+
78+
if opt_disabled!(opts, PASSTHROUGH_SUBCLASS) {
79+
if is_subclass_by_flag!(ob_type, Py_TPFLAGS_UNICODE_SUBCLASS) {
80+
return ObType::StrSubclass;
81+
} else if is_subclass_by_flag!(ob_type, Py_TPFLAGS_LONG_SUBCLASS) {
82+
return ObType::Int;
83+
} else if is_subclass_by_flag!(ob_type, Py_TPFLAGS_LIST_SUBCLASS) {
84+
return ObType::List;
85+
} else if is_subclass_by_flag!(ob_type, Py_TPFLAGS_DICT_SUBCLASS) {
86+
return ObType::Dict;
87+
}
88+
}
89+
90+
if is_subclass_by_type!(ob_type, ENUM_TYPE) {
91+
return ObType::Enum;
92+
}
93+
94+
if opt_disabled!(opts, PASSTHROUGH_DATACLASS) && pydict_contains!(ob_type, DATACLASS_FIELDS_STR)
95+
{
96+
return ObType::Dataclass;
97+
}
98+
99+
if unlikely!(opt_enabled!(opts, SERIALIZE_NUMPY)) {
100+
if is_numpy_scalar(ob_type) {
101+
return ObType::NumpyScalar;
102+
} else if is_numpy_array(ob_type) {
103+
return ObType::NumpyArray;
104+
}
105+
}
106+
107+
ObType::Unknown
108+
}

src/serialize/per_type/dataclass.rs

Lines changed: 32 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -1,82 +1,60 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
22

3-
use crate::opt::*;
43
use crate::serialize::error::SerializeError;
5-
use crate::serialize::serializer::{PyObjectSerializer, RECURSION_LIMIT};
4+
use crate::serialize::serializer::PyObjectSerializer;
5+
use crate::serialize::state::SerializerState;
66
use crate::str::unicode_to_str;
7-
use crate::typeref::*;
7+
use crate::typeref::{
8+
DATACLASS_FIELDS_STR, DICT_STR, FIELD_TYPE, FIELD_TYPE_STR, SLOTS_STR, STR_TYPE,
9+
};
810

911
use serde::ser::{Serialize, SerializeMap, Serializer};
1012

1113
use std::ptr::NonNull;
1214

13-
pub struct DataclassGenericSerializer {
14-
ptr: *mut pyo3_ffi::PyObject,
15-
opts: Opt,
16-
default_calls: u8,
17-
recursion: u8,
18-
default: Option<NonNull<pyo3_ffi::PyObject>>,
15+
#[repr(transparent)]
16+
pub struct DataclassGenericSerializer<'a> {
17+
previous: &'a PyObjectSerializer,
1918
}
2019

21-
impl DataclassGenericSerializer {
22-
pub fn new(
23-
ptr: *mut pyo3_ffi::PyObject,
24-
opts: Opt,
25-
default_calls: u8,
26-
recursion: u8,
27-
default: Option<NonNull<pyo3_ffi::PyObject>>,
28-
) -> Self {
29-
DataclassGenericSerializer {
30-
ptr: ptr,
31-
opts: opts,
32-
default_calls: default_calls,
33-
recursion: recursion + 1,
34-
default: default,
35-
}
20+
impl<'a> DataclassGenericSerializer<'a> {
21+
pub fn new(previous: &'a PyObjectSerializer) -> Self {
22+
Self { previous: previous }
3623
}
3724
}
3825

39-
impl Serialize for DataclassGenericSerializer {
26+
impl<'a> Serialize for DataclassGenericSerializer<'a> {
4027
#[inline(never)]
4128
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
4229
where
4330
S: Serializer,
4431
{
45-
if unlikely!(self.recursion == RECURSION_LIMIT) {
32+
if unlikely!(self.previous.state.recursion_limit()) {
4633
err!(SerializeError::RecursionLimit)
4734
}
48-
let dict = ffi!(PyObject_GetAttr(self.ptr, DICT_STR));
49-
let ob_type = ob_type!(self.ptr);
35+
let dict = ffi!(PyObject_GetAttr(self.previous.ptr, DICT_STR));
36+
let ob_type = ob_type!(self.previous.ptr);
5037
if unlikely!(dict.is_null()) {
5138
ffi!(PyErr_Clear());
5239
DataclassFallbackSerializer::new(
53-
self.ptr,
54-
self.opts,
55-
self.default_calls,
56-
self.recursion,
57-
self.default,
40+
self.previous.ptr,
41+
self.previous.state,
42+
self.previous.default,
5843
)
5944
.serialize(serializer)
6045
} else if pydict_contains!(ob_type, SLOTS_STR) {
6146
let ret = DataclassFallbackSerializer::new(
62-
self.ptr,
63-
self.opts,
64-
self.default_calls,
65-
self.recursion,
66-
self.default,
47+
self.previous.ptr,
48+
self.previous.state,
49+
self.previous.default,
6750
)
6851
.serialize(serializer);
6952
ffi!(Py_DECREF(dict));
7053
ret
7154
} else {
72-
let ret = DataclassFastSerializer::new(
73-
dict,
74-
self.opts,
75-
self.default_calls,
76-
self.recursion,
77-
self.default,
78-
)
79-
.serialize(serializer);
55+
let ret =
56+
DataclassFastSerializer::new(dict, self.previous.state, self.previous.default)
57+
.serialize(serializer);
8058
ffi!(Py_DECREF(dict));
8159
ret
8260
}
@@ -85,25 +63,19 @@ impl Serialize for DataclassGenericSerializer {
8563

8664
pub struct DataclassFastSerializer {
8765
ptr: *mut pyo3_ffi::PyObject,
88-
opts: Opt,
89-
default_calls: u8,
90-
recursion: u8,
66+
state: SerializerState,
9167
default: Option<NonNull<pyo3_ffi::PyObject>>,
9268
}
9369

9470
impl DataclassFastSerializer {
9571
pub fn new(
9672
ptr: *mut pyo3_ffi::PyObject,
97-
opts: Opt,
98-
default_calls: u8,
99-
recursion: u8,
73+
state: SerializerState,
10074
default: Option<NonNull<pyo3_ffi::PyObject>>,
10175
) -> Self {
10276
DataclassFastSerializer {
10377
ptr: ptr,
104-
opts: opts,
105-
default_calls: default_calls,
106-
recursion: recursion,
78+
state: state.copy_for_recursive_call(),
10779
default: default,
10880
}
10981
}
@@ -142,13 +114,7 @@ impl Serialize for DataclassFastSerializer {
142114
if unlikely!(key_as_str.as_bytes()[0] == b'_') {
143115
continue;
144116
}
145-
let pyvalue = PyObjectSerializer::new(
146-
value,
147-
self.opts,
148-
self.default_calls,
149-
self.recursion,
150-
self.default,
151-
);
117+
let pyvalue = PyObjectSerializer::new(value, self.state, self.default);
152118
map.serialize_key(key_as_str).unwrap();
153119
map.serialize_value(&pyvalue)?;
154120
}
@@ -158,25 +124,19 @@ impl Serialize for DataclassFastSerializer {
158124

159125
pub struct DataclassFallbackSerializer {
160126
ptr: *mut pyo3_ffi::PyObject,
161-
opts: Opt,
162-
default_calls: u8,
163-
recursion: u8,
127+
state: SerializerState,
164128
default: Option<NonNull<pyo3_ffi::PyObject>>,
165129
}
166130

167131
impl DataclassFallbackSerializer {
168132
pub fn new(
169133
ptr: *mut pyo3_ffi::PyObject,
170-
opts: Opt,
171-
default_calls: u8,
172-
recursion: u8,
134+
state: SerializerState,
173135
default: Option<NonNull<pyo3_ffi::PyObject>>,
174136
) -> Self {
175137
DataclassFallbackSerializer {
176138
ptr: ptr,
177-
opts: opts,
178-
default_calls: default_calls,
179-
recursion: recursion,
139+
state: state.copy_for_recursive_call(),
180140
default: default,
181141
}
182142
}
@@ -226,13 +186,7 @@ impl Serialize for DataclassFallbackSerializer {
226186
let value = ffi!(PyObject_GetAttr(self.ptr, attr));
227187
debug_assert!(ffi!(Py_REFCNT(value)) >= 2);
228188
ffi!(Py_DECREF(value));
229-
let pyvalue = PyObjectSerializer::new(
230-
value,
231-
self.opts,
232-
self.default_calls,
233-
self.recursion,
234-
self.default,
235-
);
189+
let pyvalue = PyObjectSerializer::new(value, self.state, self.default);
236190

237191
map.serialize_key(key_as_str).unwrap();
238192
map.serialize_value(&pyvalue)?

src/serialize/per_type/datetime.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ impl Date {
4141
pub fn new(ptr: *mut pyo3_ffi::PyObject) -> Self {
4242
Date { ptr: ptr }
4343
}
44-
#[cfg_attr(feature = "optimize", optimize(size))]
44+
4545
pub fn write_buf(&self, buf: &mut DateTimeBuffer) {
4646
{
4747
let year = ffi!(PyDateTime_GET_YEAR(self.ptr));
@@ -66,6 +66,7 @@ impl Date {
6666
}
6767
}
6868
impl Serialize for Date {
69+
#[cold]
6970
#[inline(never)]
7071
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
7172
where
@@ -93,7 +94,7 @@ impl Time {
9394
opts: opts,
9495
}
9596
}
96-
#[cfg_attr(feature = "optimize", optimize(size))]
97+
9798
pub fn write_buf(&self, buf: &mut DateTimeBuffer) -> Result<(), TimeError> {
9899
if unsafe { (*(self.ptr as *mut pyo3_ffi::PyDateTime_Time)).hastzinfo == 1 } {
99100
return Err(TimeError::HasTimezone);
@@ -115,6 +116,7 @@ impl Time {
115116
}
116117

117118
impl Serialize for Time {
119+
#[cold]
118120
#[inline(never)]
119121
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
120122
where

0 commit comments

Comments
 (0)