diff --git a/develop b/develop index d0519d5809b751939f67cf4688dc6349ab17cead_ZGV2ZWxvcA==..b6ef49274d2962798362ac2cf73cd0ee27d30af4_ZGV2ZWxvcA== 100755 --- a/develop +++ b/develop @@ -2,6 +2,6 @@ rm -f target/wheels/* -maturin build --no-sdist --manylinux 1 -i python3 --release "$@" +maturin build --no-sdist --manylinux 2014 -i python3 --release "$@" pip install --force $(find target/wheels -name "*cp3*") diff --git a/src/deserialize/decode.rs b/src/deserialize/decode.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL2Rlc2VyaWFsaXplL2RlY29kZS5ycw==..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL2Rlc2VyaWFsaXplL2RlY29kZS5ycw== 100644 --- a/src/deserialize/decode.rs +++ b/src/deserialize/decode.rs @@ -119,10 +119,10 @@ where E: de::Error, { - Ok(nonnull!(str_to_pyobject!(value.as_str()))) + Ok(nonnull!(unicode_from_str(value.as_str()))) } fn visit_borrowed_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error, { @@ -123,13 +123,13 @@ } fn visit_borrowed_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error, { - Ok(nonnull!(str_to_pyobject!(value))) + Ok(nonnull!(unicode_from_str(value))) } fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error, { @@ -130,10 +130,10 @@ } fn visit_str<E>(self, value: &str) -> Result<Self::Value, E> where E: de::Error, { - Ok(nonnull!(str_to_pyobject!(value))) + Ok(nonnull!(unicode_from_str(value))) } fn visit_seq<A>(self, mut seq: A) -> Result<Self::Value, A::Error> @@ -178,7 +178,7 @@ let entry = map.entry(&hash).or_insert_with( || hash, || { - let pyob = str_to_pyobject!(&key); + let pyob = unicode_from_str(&key); CachedKey::new(pyob, hash_str(pyob)) }, ); @@ -187,7 +187,7 @@ pyhash = tmp.1; } } else { - pykey = str_to_pyobject!(&key); + pykey = unicode_from_str(&key); pyhash = hash_str(pykey); } let value = map.next_value_seed(self)?; diff --git a/src/lib.rs b/src/lib.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL2xpYi5ycw==..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL2xpYi5ycw== 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -154,6 +154,7 @@ } #[cold] +#[inline(never)] fn raise_loads_exception(msg: Cow<str>) -> *mut PyObject { unsafe { let err_msg = @@ -171,6 +172,7 @@ } #[cold] +#[inline(never)] fn raise_dumps_exception(msg: Cow<str>) -> *mut PyObject { unsafe { let err_msg = diff --git a/src/serialize/dataclass.rs b/src/serialize/dataclass.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9kYXRhY2xhc3MucnM=..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9kYXRhY2xhc3MucnM= 100644 --- a/src/serialize/dataclass.rs +++ b/src/serialize/dataclass.rs @@ -11,7 +11,85 @@ use std::ptr::NonNull; -pub struct DataclassSerializer { +pub struct DataclassFastSerializer { + dict: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, +} + +impl DataclassFastSerializer { + pub fn new( + dict: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, + ) -> Self { + DataclassFastSerializer { + dict: dict, + opts: opts, + default_calls: default_calls, + recursion: recursion, + default: default, + } + } +} + +impl<'p> Serialize for DataclassFastSerializer { + #[inline(never)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let len = unsafe { PyDict_GET_SIZE(self.dict) as usize }; + if unlikely!(len == 0) { + return serializer.serialize_map(Some(0)).unwrap().end(); + } + let mut map = serializer.serialize_map(None).unwrap(); + let mut pos = 0isize; + let mut str_size: pyo3::ffi::Py_ssize_t = 0; + let mut key: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); + let mut value: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); + for _ in 0..=len - 1 { + unsafe { + pyo3::ffi::_PyDict_Next( + self.dict, + &mut pos, + &mut key, + &mut value, + std::ptr::null_mut(), + ) + }; + if unlikely!(ob_type!(key) != STR_TYPE) { + err!(KEY_MUST_BE_STR) + } + { + let data = read_utf8_from_str(key, &mut str_size); + if unlikely!(data.is_null()) { + err!(INVALID_STR) + } + let key_as_str = str_from_slice!(data, str_size); + if unlikely!(key_as_str.as_bytes()[0] == b'_') { + continue; + } + map.serialize_key(key_as_str).unwrap(); + } + + map.serialize_value(&PyObjectSerializer::new( + value, + self.opts, + self.default_calls, + self.recursion + 1, + self.default, + ))?; + } + map.end() + } +} + +pub struct DataclassFallbackSerializer { ptr: *mut pyo3::ffi::PyObject, opts: Opt, default_calls: u8, @@ -19,7 +97,7 @@ default: Option<NonNull<pyo3::ffi::PyObject>>, } -impl DataclassSerializer { +impl DataclassFallbackSerializer { pub fn new( ptr: *mut pyo3::ffi::PyObject, opts: Opt, @@ -27,7 +105,7 @@ recursion: u8, default: Option<NonNull<pyo3::ffi::PyObject>>, ) -> Self { - DataclassSerializer { + DataclassFallbackSerializer { ptr: ptr, opts: opts, default_calls: default_calls, @@ -37,7 +115,7 @@ } } -impl<'p> Serialize for DataclassSerializer { +impl<'p> Serialize for DataclassFallbackSerializer { #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where @@ -84,7 +162,7 @@ let value = ffi!(PyObject_GetAttr(self.ptr, attr)); ffi!(Py_DECREF(value)); - map.serialize_value(&SerializePyObject::new( + map.serialize_value(&PyObjectSerializer::new( value, self.opts, self.default_calls, diff --git a/src/serialize/datetime.rs b/src/serialize/datetime.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9kYXRldGltZS5ycw==..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9kYXRldGltZS5ycw== 100644 --- a/src/serialize/datetime.rs +++ b/src/serialize/datetime.rs @@ -56,6 +56,7 @@ } } impl<'p> Serialize for Date { + #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -108,6 +109,7 @@ } impl<'p> Serialize for Time { + #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -266,6 +268,7 @@ } impl<'p> Serialize for DateTime { + #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, diff --git a/src/serialize/default.rs b/src/serialize/default.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9kZWZhdWx0LnJz..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9kZWZhdWx0LnJz 100644 --- a/src/serialize/default.rs +++ b/src/serialize/default.rs @@ -8,10 +8,11 @@ use std::ptr::NonNull; -macro_rules! obj_name { - ($obj:expr) => { - unsafe { CStr::from_ptr((*$obj).tp_name).to_string_lossy() } - }; +#[cold] +#[inline(never)] +fn format_err(ptr: *mut pyo3::ffi::PyObject) -> String { + let name = unsafe { CStr::from_ptr((*ob_type!(ptr)).tp_name).to_string_lossy() }; + format_args!("Type is not JSON serializable: {}", name).to_string() } pub struct DefaultSerializer { @@ -57,8 +58,5 @@ std::ptr::null_mut() as *mut pyo3::ffi::PyObject )); if unlikely!(default_obj.is_null()) { - err!(format_args!( - "Type is not JSON serializable: {}", - obj_name!(ob_type!(self.ptr)) - )) + err!(format_err(self.ptr)) } else { @@ -64,5 +62,5 @@ } else { - let res = SerializePyObject::new( + let res = PyObjectSerializer::new( default_obj, self.opts, self.default_calls + 1, @@ -74,10 +72,7 @@ res } } - None => err!(format_args!( - "Type is not JSON serializable: {}", - obj_name!(ob_type!(self.ptr)) - )), + None => err!(format_err(self.ptr)), } } } diff --git a/src/serialize/dict.rs b/src/serialize/dict.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9kaWN0LnJz..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9kaWN0LnJz 100644 --- a/src/serialize/dict.rs +++ b/src/serialize/dict.rs @@ -13,6 +13,79 @@ use smallvec::SmallVec; use std::ptr::NonNull; +pub struct Dict { + ptr: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, + len: usize, +} + +impl Dict { + pub fn new( + ptr: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, + len: usize, + ) -> Self { + Dict { + ptr: ptr, + opts: opts, + default_calls: default_calls, + recursion: recursion, + default: default, + len: len, + } + } +} + +impl<'p> Serialize for Dict { + #[inline(never)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut map = serializer.serialize_map(None).unwrap(); + let mut pos = 0isize; + let mut str_size: pyo3::ffi::Py_ssize_t = 0; + let mut key: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); + let mut value: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); + for _ in 0..=self.len - 1 { + unsafe { + pyo3::ffi::_PyDict_Next( + self.ptr, + &mut pos, + &mut key, + &mut value, + std::ptr::null_mut(), + ) + }; + if unlikely!(ob_type!(key) != STR_TYPE) { + err!(KEY_MUST_BE_STR) + } + { + let data = read_utf8_from_str(key, &mut str_size); + if unlikely!(data.is_null()) { + err!(INVALID_STR) + } + map.serialize_key(str_from_slice!(data, str_size)).unwrap(); + } + + map.serialize_value(&PyObjectSerializer::new( + value, + self.opts, + self.default_calls, + self.recursion + 1, + self.default, + ))?; + } + map.end() + } +} + pub struct DictSortedKey { ptr: *mut pyo3::ffi::PyObject, opts: Opt, @@ -80,7 +153,7 @@ for (key, val) in items.iter() { map.serialize_entry( key, - &SerializePyObject::new( + &PyObjectSerializer::new( *val, self.opts, self.default_calls, @@ -101,7 +174,7 @@ UnsupportedType, } -pub struct NonStrKey { +pub struct DictNonStrKey { ptr: *mut pyo3::ffi::PyObject, opts: Opt, default_calls: u8, @@ -110,7 +183,7 @@ len: usize, } -impl NonStrKey { +impl DictNonStrKey { pub fn new( ptr: *mut pyo3::ffi::PyObject, opts: Opt, @@ -119,7 +192,7 @@ default: Option<NonNull<pyo3::ffi::PyObject>>, len: usize, ) -> Self { - NonStrKey { + DictNonStrKey { ptr: ptr, opts: opts, default_calls: default_calls, @@ -225,7 +298,7 @@ } } -impl<'p> Serialize for NonStrKey { +impl<'p> Serialize for DictNonStrKey { #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where @@ -283,7 +356,7 @@ for (key, val) in items.iter() { map.serialize_entry( str_from_slice!(key.as_ptr(), key.len()), - &SerializePyObject::new( + &PyObjectSerializer::new( *val, self.opts, self.default_calls, diff --git a/src/serialize/encode.rs b/src/serialize/encode.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9lbmNvZGUucnM=..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9lbmNvZGUucnM= 100644 --- a/src/serialize/encode.rs +++ b/src/serialize/encode.rs @@ -7,4 +7,5 @@ use crate::serialize::datetime::*; use crate::serialize::default::*; use crate::serialize::dict::*; +use crate::serialize::list::*; use crate::serialize::numpy::*; @@ -10,4 +11,5 @@ use crate::serialize::numpy::*; +use crate::serialize::str::*; use crate::serialize::tuple::*; use crate::serialize::uuid::*; use crate::serialize::writer::*; @@ -38,7 +40,7 @@ _ => {} } buf.prefetch(); - let obj = SerializePyObject::with_obtype(ptr, obtype, opts, 0, 0, default); + let obj = PyObjectSerializer::with_obtype(ptr, obtype, opts, 0, 0, default); let res; if likely!(opts & INDENT_2 != INDENT_2) { res = serde_json::to_writer(&mut buf, &obj); @@ -127,7 +129,7 @@ ObType::Uuid } else if (*(ob_type as *mut LocalPyTypeObject)).ob_type == ENUM_TYPE { ObType::Enum - } else if is_subclass!(ob_type, Py_TPFLAGS_UNICODE_SUBCLASS) - && opts & PASSTHROUGH_SUBCLASS == 0 + } else if opts & PASSTHROUGH_SUBCLASS == 0 + && is_subclass!(ob_type, Py_TPFLAGS_UNICODE_SUBCLASS) { ObType::StrSubclass @@ -132,6 +134,6 @@ { ObType::StrSubclass - } else if is_subclass!(ob_type, Py_TPFLAGS_LONG_SUBCLASS) - && opts & PASSTHROUGH_SUBCLASS == 0 + } else if opts & PASSTHROUGH_SUBCLASS == 0 + && is_subclass!(ob_type, Py_TPFLAGS_LONG_SUBCLASS) { ObType::Int @@ -136,6 +138,6 @@ { ObType::Int - } else if is_subclass!(ob_type, Py_TPFLAGS_LIST_SUBCLASS) - && opts & PASSTHROUGH_SUBCLASS == 0 + } else if opts & PASSTHROUGH_SUBCLASS == 0 + && is_subclass!(ob_type, Py_TPFLAGS_LIST_SUBCLASS) { ObType::List @@ -140,7 +142,7 @@ { ObType::List - } else if is_subclass!(ob_type, Py_TPFLAGS_DICT_SUBCLASS) - && opts & PASSTHROUGH_SUBCLASS == 0 + } else if opts & PASSTHROUGH_SUBCLASS == 0 + && is_subclass!(ob_type, Py_TPFLAGS_DICT_SUBCLASS) { ObType::Dict } else if opts & PASSTHROUGH_DATACLASS == 0 @@ -157,7 +159,7 @@ } } -pub struct SerializePyObject { +pub struct PyObjectSerializer { ptr: *mut pyo3::ffi::PyObject, obtype: ObType, opts: Opt, @@ -166,7 +168,7 @@ default: Option<NonNull<pyo3::ffi::PyObject>>, } -impl SerializePyObject { +impl PyObjectSerializer { #[inline] pub fn new( ptr: *mut pyo3::ffi::PyObject, @@ -175,7 +177,7 @@ recursion: u8, default: Option<NonNull<pyo3::ffi::PyObject>>, ) -> Self { - SerializePyObject { + PyObjectSerializer { ptr: ptr, obtype: pyobject_to_obtype(ptr, opts), opts: opts, @@ -194,7 +196,7 @@ recursion: u8, default: Option<NonNull<pyo3::ffi::PyObject>>, ) -> Self { - SerializePyObject { + PyObjectSerializer { ptr: ptr, obtype: obtype, opts: opts, @@ -205,7 +207,7 @@ } } -impl<'p> Serialize for SerializePyObject { +impl<'p> Serialize for PyObjectSerializer { fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, @@ -219,14 +221,7 @@ } serializer.serialize_str(str_from_slice!(uni, str_size)) } - ObType::StrSubclass => { - let mut str_size: pyo3::ffi::Py_ssize_t = 0; - let uni = ffi!(PyUnicode_AsUTF8AndSize(self.ptr, &mut str_size)) as *const u8; - if unlikely!(uni.is_null()) { - err!(INVALID_STR) - } - serializer.serialize_str(str_from_slice!(uni, str_size)) - } + ObType::StrSubclass => StrSubclassSerializer::new(self.ptr).serialize(serializer), ObType::Int => { let val = ffi!(PyLong_AsLongLong(self.ptr)); if unlikely!(val == -1) && !ffi!(PyErr_Occurred()).is_null() { @@ -256,39 +251,13 @@ if unlikely!(len == 0) { serializer.serialize_map(Some(0)).unwrap().end() } else if likely!(self.opts & SORT_OR_NON_STR_KEYS == 0) { - let mut map = serializer.serialize_map(None).unwrap(); - let mut pos = 0isize; - let mut str_size: pyo3::ffi::Py_ssize_t = 0; - let mut key: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); - let mut value: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); - for _ in 0..=len - 1 { - unsafe { - pyo3::ffi::_PyDict_Next( - self.ptr, - &mut pos, - &mut key, - &mut value, - std::ptr::null_mut(), - ) - }; - if unlikely!(ob_type!(key) != STR_TYPE) { - err!(KEY_MUST_BE_STR) - } - { - let data = read_utf8_from_str(key, &mut str_size); - if unlikely!(data.is_null()) { - err!(INVALID_STR) - } - map.serialize_key(str_from_slice!(data, str_size)).unwrap(); - } - - map.serialize_value(&SerializePyObject::new( - value, - self.opts, - self.default_calls, - self.recursion + 1, - self.default, - ))?; - } - map.end() + Dict::new( + self.ptr, + self.opts, + self.default_calls, + self.recursion, + self.default, + len, + ) + .serialize(serializer) } else if self.opts & NON_STR_KEYS != 0 { @@ -294,5 +263,5 @@ } else if self.opts & NON_STR_KEYS != 0 { - NonStrKey::new( + DictNonStrKey::new( self.ptr, self.opts, self.default_calls, @@ -318,6 +287,6 @@ err!(RECURSION_LIMIT_REACHED) } let len = ffi!(PyList_GET_SIZE(self.ptr)) as usize; - if len == 0 { + if unlikely!(len == 0) { serializer.serialize_seq(Some(0)).unwrap().end() } else { @@ -322,28 +291,13 @@ serializer.serialize_seq(Some(0)).unwrap().end() } else { - let mut type_ptr = std::ptr::null_mut(); - let mut ob_type = ObType::Str; - - let mut seq = serializer.serialize_seq(None).unwrap(); - for i in 0..=len - 1 { - let elem = unsafe { - *(*(self.ptr as *mut pyo3::ffi::PyListObject)) - .ob_item - .offset(i as isize) - }; - if ob_type!(elem) != type_ptr { - type_ptr = ob_type!(elem); - ob_type = pyobject_to_obtype(elem, self.opts); - } - seq.serialize_element(&SerializePyObject::with_obtype( - elem, - ob_type, - self.opts, - self.default_calls, - self.recursion + 1, - self.default, - ))?; - } - seq.end() + ListSerializer::new( + self.ptr, + self.opts, + self.default_calls, + self.recursion, + self.default, + len, + ) + .serialize(serializer) } } @@ -348,20 +302,15 @@ } } - ObType::Tuple => { - let mut seq = serializer.serialize_seq(None).unwrap(); - for elem in PyTupleIterator::new(self.ptr) { - seq.serialize_element(&SerializePyObject::new( - elem.as_ptr(), - self.opts, - self.default_calls, - self.recursion + 1, - self.default, - ))? - } - seq.end() - } + ObType::Tuple => TupleSerializer::new( + self.ptr, + self.opts, + self.default_calls, + self.recursion, + self.default, + ) + .serialize(serializer), ObType::Dataclass => { if unlikely!(self.recursion == RECURSION_LIMIT) { err!(RECURSION_LIMIT_REACHED) } let dict = ffi!(PyObject_GetAttr(self.ptr, DICT_STR)); @@ -363,7 +312,7 @@ ObType::Dataclass => { if unlikely!(self.recursion == RECURSION_LIMIT) { err!(RECURSION_LIMIT_REACHED) } let dict = ffi!(PyObject_GetAttr(self.ptr, DICT_STR)); - if !dict.is_null() { + if likely!(!dict.is_null()) { ffi!(Py_DECREF(dict)); @@ -369,46 +318,11 @@ ffi!(Py_DECREF(dict)); - let len = unsafe { PyDict_GET_SIZE(dict) as usize }; - if unlikely!(len == 0) { - return serializer.serialize_map(Some(0)).unwrap().end(); - } - let mut map = serializer.serialize_map(None).unwrap(); - let mut pos = 0isize; - let mut str_size: pyo3::ffi::Py_ssize_t = 0; - let mut key: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); - let mut value: *mut pyo3::ffi::PyObject = std::ptr::null_mut(); - for _ in 0..=len - 1 { - unsafe { - pyo3::ffi::_PyDict_Next( - dict, - &mut pos, - &mut key, - &mut value, - std::ptr::null_mut(), - ) - }; - if unlikely!(ob_type!(key) != STR_TYPE) { - err!(KEY_MUST_BE_STR) - } - { - let data = read_utf8_from_str(key, &mut str_size); - if unlikely!(data.is_null()) { - err!(INVALID_STR) - } - let key_as_str = str_from_slice!(data, str_size); - if unlikely!(key_as_str.as_bytes()[0] == b'_') { - continue; - } - map.serialize_key(key_as_str).unwrap(); - } - - map.serialize_value(&SerializePyObject::new( - value, - self.opts, - self.default_calls, - self.recursion + 1, - self.default, - ))?; - } - map.end() + DataclassFastSerializer::new( + dict, + self.opts, + self.default_calls, + self.recursion, + self.default, + ) + .serialize(serializer) } else { unsafe { pyo3::ffi::PyErr_Clear() }; @@ -413,6 +327,6 @@ } else { unsafe { pyo3::ffi::PyErr_Clear() }; - DataclassSerializer::new( + DataclassFallbackSerializer::new( self.ptr, self.opts, self.default_calls, @@ -425,7 +339,7 @@ ObType::Enum => { let value = ffi!(PyObject_GetAttr(self.ptr, VALUE_STR)); ffi!(Py_DECREF(value)); - SerializePyObject::new( + PyObjectSerializer::new( value, self.opts, self.default_calls, diff --git a/src/serialize/list.rs b/src/serialize/list.rs new file mode 100644 index 0000000000000000000000000000000000000000..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9saXN0LnJz --- /dev/null +++ b/src/serialize/list.rs @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: (Apache-2.0 OR MIT) + +use crate::opt::*; +use crate::serialize::encode::*; + +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, + default: Option<NonNull<pyo3::ffi::PyObject>>, + len: usize, +} + +impl ListSerializer { + pub fn new( + ptr: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, + len: usize, + ) -> Self { + ListSerializer { + ptr: ptr, + opts: opts, + default_calls: default_calls, + recursion: recursion, + default: default, + len: len, + } + } +} + +impl<'p> Serialize for ListSerializer { + #[inline(never)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut type_ptr = std::ptr::null_mut(); + let mut ob_type = ObType::Str; + + let mut seq = serializer.serialize_seq(None).unwrap(); + for i in 0..=self.len - 1 { + let elem = unsafe { + *(*(self.ptr as *mut pyo3::ffi::PyListObject)) + .ob_item + .offset(i as isize) + }; + if ob_type!(elem) != type_ptr { + type_ptr = ob_type!(elem); + ob_type = pyobject_to_obtype(elem, self.opts); + } + seq.serialize_element(&PyObjectSerializer::with_obtype( + elem, + ob_type, + self.opts, + self.default_calls, + self.recursion + 1, + self.default, + ))?; + } + seq.end() + } +} diff --git a/src/serialize/mod.rs b/src/serialize/mod.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS9tb2QucnM=..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9tb2QucnM= 100644 --- a/src/serialize/mod.rs +++ b/src/serialize/mod.rs @@ -5,4 +5,5 @@ mod default; mod dict; mod encode; +mod list; mod numpy; @@ -8,4 +9,5 @@ mod numpy; +mod str; mod tuple; mod uuid; mod writer; diff --git a/src/serialize/str.rs b/src/serialize/str.rs new file mode 100644 index 0000000000000000000000000000000000000000..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS9zdHIucnM= --- /dev/null +++ b/src/serialize/str.rs @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: (Apache-2.0 OR MIT) + +use crate::exc::*; + +use serde::ser::{Serialize, Serializer}; + +#[repr(transparent)] +pub struct StrSubclassSerializer { + ptr: *mut pyo3::ffi::PyObject, +} + +impl StrSubclassSerializer { + pub fn new(ptr: *mut pyo3::ffi::PyObject) -> Self { + StrSubclassSerializer { ptr: ptr } + } +} + +impl<'p> Serialize for StrSubclassSerializer { + #[inline(never)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut str_size: pyo3::ffi::Py_ssize_t = 0; + let uni = ffi!(PyUnicode_AsUTF8AndSize(self.ptr, &mut str_size)) as *const u8; + if unlikely!(uni.is_null()) { + err!(INVALID_STR) + } + serializer.serialize_str(str_from_slice!(uni, str_size)) + } +} diff --git a/src/serialize/tuple.rs b/src/serialize/tuple.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS90dXBsZS5ycw==..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS90dXBsZS5ycw== 100644 --- a/src/serialize/tuple.rs +++ b/src/serialize/tuple.rs @@ -1,4 +1,8 @@ // SPDX-License-Identifier: (Apache-2.0 OR MIT) +use crate::opt::*; +use crate::serialize::encode::*; + +use serde::ser::{Serialize, SerializeSeq, Serializer}; use std::ptr::NonNull; @@ -3,8 +7,10 @@ use std::ptr::NonNull; -pub struct PyTupleIterator { - list: *mut pyo3::ffi::PyObject, - len: isize, - idx: isize, +pub struct TupleSerializer { + ptr: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, } @@ -9,12 +15,20 @@ } -impl PyTupleIterator { - pub fn new(list: *mut pyo3::ffi::PyObject) -> Self { - PyTupleIterator { - list: list, - len: ffi!(PyTuple_GET_SIZE(list)), - idx: 0, +impl TupleSerializer { + pub fn new( + ptr: *mut pyo3::ffi::PyObject, + opts: Opt, + default_calls: u8, + recursion: u8, + default: Option<NonNull<pyo3::ffi::PyObject>>, + ) -> Self { + TupleSerializer { + ptr: ptr, + opts: opts, + default_calls: default_calls, + recursion: recursion, + default: default, } } } @@ -17,16 +31,21 @@ } } } -impl Iterator for PyTupleIterator { - type Item = NonNull<pyo3::ffi::PyObject>; - - #[inline] - fn next(&mut self) -> Option<NonNull<pyo3::ffi::PyObject>> { - if self.len == self.idx { - None - } else { - let item = nonnull!(ffi!(PyTuple_GET_ITEM(self.list, self.idx as isize))); - self.idx += 1; - Some(item) +impl<'p> Serialize for TupleSerializer { + #[inline(never)] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: Serializer, + { + let mut seq = serializer.serialize_seq(None).unwrap(); + for i in 0..=ffi!(PyTuple_GET_SIZE(self.ptr)) - 1 { + let elem = nonnull!(ffi!(PyTuple_GET_ITEM(self.ptr, i as isize))); + seq.serialize_element(&PyObjectSerializer::new( + elem.as_ptr(), + self.opts, + self.default_calls, + self.recursion + 1, + self.default, + ))? } @@ -32,3 +51,4 @@ } + seq.end() } } diff --git a/src/serialize/uuid.rs b/src/serialize/uuid.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3NlcmlhbGl6ZS91dWlkLnJz..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3NlcmlhbGl6ZS91dWlkLnJz 100644 --- a/src/serialize/uuid.rs +++ b/src/serialize/uuid.rs @@ -51,6 +51,7 @@ } } impl<'p> Serialize for UUID { + #[inline(never)] fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer, diff --git a/src/unicode.rs b/src/unicode.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3VuaWNvZGUucnM=..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3VuaWNvZGUucnM= 100644 --- a/src/unicode.rs +++ b/src/unicode.rs @@ -109,7 +109,6 @@ } } -#[inline] pub fn read_utf8_from_str(op: *mut PyObject, str_size: &mut Py_ssize_t) -> *const u8 { unsafe { if (*op.cast::<PyASCIIObject>()).state & STATE_COMPACT_ASCII == STATE_COMPACT_ASCII { diff --git a/src/util.rs b/src/util.rs index d0519d5809b751939f67cf4688dc6349ab17cead_c3JjL3V0aWwucnM=..b6ef49274d2962798362ac2cf73cd0ee27d30af4_c3JjL3V0aWwucnM= 100644 --- a/src/util.rs +++ b/src/util.rs @@ -42,12 +42,6 @@ }; } -macro_rules! str_to_pyobject { - ($obj:expr) => { - crate::unicode::unicode_from_str($obj) - }; -} - macro_rules! ffi { ($fn:ident()) => { unsafe { pyo3::ffi::$fn() }