From 10180d5dada5f2807f90b0a89fce0f88ad67670c Mon Sep 17 00:00:00 2001 From: ijl Date: Mon, 23 Dec 2024 16:21:17 +0000 Subject: [PATCH] edition 2024 compatibility, MSRV 1.82 --- .github/workflows/debug.yaml | 4 +- Cargo.toml | 2 +- README.md | 2 +- build.rs | 4 +- src/ffi/buffer.rs | 2 +- src/ffi/bytes.rs | 4 +- src/ffi/fragment.rs | 174 ++++++------- src/ffi/long.rs | 2 +- src/ffi/yyjson.rs | 6 +- src/lib.rs | 332 +++++++++++++------------ src/serialize/error.rs | 19 +- src/serialize/per_type/datetimelike.rs | 2 +- src/serialize/per_type/int.rs | 2 +- src/serialize/writer/str/avx512.rs | 20 +- src/serialize/writer/str/generic.rs | 30 +-- src/serialize/writer/str/sse2.rs | 28 ++- src/typeref.rs | 155 +++++++----- 17 files changed, 419 insertions(+), 369 deletions(-) diff --git a/.github/workflows/debug.yaml b/.github/workflows/debug.yaml index 1c49f8bb..5bbe4d71 100644 --- a/.github/workflows/debug.yaml +++ b/.github/workflows/debug.yaml @@ -8,8 +8,8 @@ jobs: fail-fast: false matrix: profile: [ - { rust: "1.72", features: "" }, - { rust: "1.72", features: "--features=yyjson" }, + { rust: "1.82", features: "" }, + { rust: "1.82", features: "--features=yyjson" }, { rust: "nightly-2024-11-22", features: "--features=avx512,yyjson,unstable-simd" }, ] python: [ diff --git a/Cargo.toml b/Cargo.toml index 4a6213ec..c94525de 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["ijl "] description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" edition = "2021" resolver = "2" -rust-version = "1.72" +rust-version = "1.82" license = "Apache-2.0 OR MIT" repository = "https://github.com/ijl/orjson" homepage = "https://github.com/ijl/orjson" diff --git a/README.md b/README.md index 75b1d4f2..1315974d 100644 --- a/README.md +++ b/README.md @@ -1066,7 +1066,7 @@ No, it supports RFC 8259. ## Packaging -To package orjson requires at least [Rust](https://www.rust-lang.org/) 1.72 +To package orjson requires at least [Rust](https://www.rust-lang.org/) 1.82 and the [maturin](https://github.com/PyO3/maturin) build tool. The recommended build command is: diff --git a/build.rs b/build.rs index b3fc40c9..8c17804d 100644 --- a/build.rs +++ b/build.rs @@ -75,7 +75,9 @@ fn main() { } Err(_) => { if env::var("CARGO_FEATURE_YYJSON").is_ok() { - panic!("yyjson was enabled but the build failed. To build with a different backend do not specify the feature.") + panic!( + "yyjson was enabled but the build failed. To build with a different backend do not specify the feature." + ) } } } diff --git a/src/ffi/buffer.rs b/src/ffi/buffer.rs index ab0b8006..cd05081a 100644 --- a/src/ffi/buffer.rs +++ b/src/ffi/buffer.rs @@ -26,5 +26,5 @@ pub struct PyMemoryViewObject { #[allow(non_snake_case)] #[inline(always)] pub unsafe fn PyMemoryView_GET_BUFFER(op: *mut PyObject) -> *const Py_buffer { - &(*op.cast::()).view + unsafe { &(*op.cast::()).view } } diff --git a/src/ffi/bytes.rs b/src/ffi/bytes.rs index f59397ea..94eb36b9 100644 --- a/src/ffi/bytes.rs +++ b/src/ffi/bytes.rs @@ -6,11 +6,11 @@ use pyo3_ffi::{PyBytesObject, PyObject, PyVarObject, Py_ssize_t}; #[allow(non_snake_case)] #[inline(always)] pub unsafe fn PyBytes_AS_STRING(op: *mut PyObject) -> *const c_char { - &(*op.cast::()).ob_sval as *const c_char + unsafe { &(*op.cast::()).ob_sval as *const c_char } } #[allow(non_snake_case)] #[inline(always)] pub unsafe fn PyBytes_GET_SIZE(op: *mut PyObject) -> Py_ssize_t { - (*op.cast::()).ob_size + unsafe { (*op.cast::()).ob_size } } diff --git a/src/ffi/fragment.rs b/src/ffi/fragment.rs index 9cfd4d7f..225a817f 100644 --- a/src/ffi/fragment.rs +++ b/src/ffi/fragment.rs @@ -27,7 +27,7 @@ fn raise_args_exception() -> *mut PyObject { null_mut() } -#[no_mangle] +#[unsafe(no_mangle)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] pub unsafe extern "C" fn orjson_fragment_tp_new( @@ -35,27 +35,31 @@ pub unsafe extern "C" fn orjson_fragment_tp_new( args: *mut PyObject, kwds: *mut PyObject, ) -> *mut PyObject { - if Py_SIZE(args) != 1 || !kwds.is_null() { - raise_args_exception(); - null_mut() - } else { - let contents = PyTuple_GET_ITEM(args, 0); - Py_INCREF(contents); - let obj = Box::new(Fragment { - ob_refcnt: 1, - ob_type: crate::typeref::FRAGMENT_TYPE, - contents: contents, - }); - Box::into_raw(obj) as *mut PyObject + unsafe { + if Py_SIZE(args) != 1 || !kwds.is_null() { + raise_args_exception(); + null_mut() + } else { + let contents = PyTuple_GET_ITEM(args, 0); + Py_INCREF(contents); + let obj = Box::new(Fragment { + ob_refcnt: 1, + ob_type: crate::typeref::FRAGMENT_TYPE, + contents: contents, + }); + Box::into_raw(obj) as *mut PyObject + } } } -#[no_mangle] +#[unsafe(no_mangle)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] pub unsafe extern "C" fn orjson_fragment_dealloc(object: *mut PyObject) { - Py_DECREF((*(object as *mut Fragment)).contents); - std::alloc::dealloc(object as *mut u8, std::alloc::Layout::new::()); + unsafe { + Py_DECREF((*(object as *mut Fragment)).contents); + std::alloc::dealloc(object as *mut u8, std::alloc::Layout::new::()); + } } #[cfg(Py_3_10)] @@ -64,76 +68,78 @@ const FRAGMENT_TP_FLAGS: c_ulong = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IMMUTABLETYPE #[cfg(not(Py_3_10))] const FRAGMENT_TP_FLAGS: c_ulong = Py_TPFLAGS_DEFAULT; -#[no_mangle] +#[unsafe(no_mangle)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] pub unsafe extern "C" fn orjson_fragmenttype_new() -> *mut PyTypeObject { - let ob = Box::new(PyTypeObject { - ob_base: PyVarObject { - ob_base: PyObject { - #[cfg(Py_3_12)] - ob_refcnt: pyo3_ffi::PyObjectObRefcnt { ob_refcnt: 0 }, - #[cfg(not(Py_3_12))] - ob_refcnt: 0, - ob_type: core::ptr::addr_of_mut!(PyType_Type), + unsafe { + let ob = Box::new(PyTypeObject { + ob_base: PyVarObject { + ob_base: PyObject { + #[cfg(Py_3_12)] + ob_refcnt: pyo3_ffi::PyObjectObRefcnt { ob_refcnt: 0 }, + #[cfg(not(Py_3_12))] + ob_refcnt: 0, + ob_type: core::ptr::addr_of_mut!(PyType_Type), + }, + ob_size: 0, }, - ob_size: 0, - }, - tp_name: "orjson.Fragment\0".as_ptr() as *const c_char, - tp_basicsize: core::mem::size_of::() as isize, - tp_itemsize: 0, - tp_dealloc: Some(orjson_fragment_dealloc), - tp_init: None, - tp_new: Some(orjson_fragment_tp_new), - tp_flags: FRAGMENT_TP_FLAGS, - // ... - tp_bases: null_mut(), - tp_cache: null_mut(), - tp_del: None, - tp_finalize: None, - tp_free: None, - tp_is_gc: None, - tp_mro: null_mut(), - tp_subclasses: null_mut(), - tp_vectorcall: None, - tp_version_tag: 0, - tp_weaklist: null_mut(), - #[cfg(not(Py_3_9))] - tp_print: None, - tp_vectorcall_offset: 0, - tp_getattr: None, - tp_setattr: None, - tp_as_async: null_mut(), - tp_repr: None, - tp_as_number: null_mut(), - tp_as_sequence: null_mut(), - tp_as_mapping: null_mut(), - tp_hash: None, - tp_call: None, - tp_str: None, - tp_getattro: None, - tp_setattro: None, - tp_as_buffer: null_mut(), - tp_doc: core::ptr::null_mut(), - tp_traverse: None, - tp_clear: None, - tp_richcompare: None, - tp_weaklistoffset: 0, - tp_iter: None, - tp_iternext: None, - tp_methods: null_mut(), - tp_members: null_mut(), - tp_getset: null_mut(), - tp_base: null_mut(), - tp_dict: null_mut(), - tp_descr_get: None, - tp_descr_set: None, - tp_dictoffset: 0, - tp_alloc: None, - #[cfg(Py_3_12)] - tp_watched: 0, - }); - let ob_ptr = Box::into_raw(ob); - PyType_Ready(ob_ptr); - ob_ptr + tp_name: "orjson.Fragment\0".as_ptr() as *const c_char, + tp_basicsize: core::mem::size_of::() as isize, + tp_itemsize: 0, + tp_dealloc: Some(orjson_fragment_dealloc), + tp_init: None, + tp_new: Some(orjson_fragment_tp_new), + tp_flags: FRAGMENT_TP_FLAGS, + // ... + tp_bases: null_mut(), + tp_cache: null_mut(), + tp_del: None, + tp_finalize: None, + tp_free: None, + tp_is_gc: None, + tp_mro: null_mut(), + tp_subclasses: null_mut(), + tp_vectorcall: None, + tp_version_tag: 0, + tp_weaklist: null_mut(), + #[cfg(not(Py_3_9))] + tp_print: None, + tp_vectorcall_offset: 0, + tp_getattr: None, + tp_setattr: None, + tp_as_async: null_mut(), + tp_repr: None, + tp_as_number: null_mut(), + tp_as_sequence: null_mut(), + tp_as_mapping: null_mut(), + tp_hash: None, + tp_call: None, + tp_str: None, + tp_getattro: None, + tp_setattro: None, + tp_as_buffer: null_mut(), + tp_doc: core::ptr::null_mut(), + tp_traverse: None, + tp_clear: None, + tp_richcompare: None, + tp_weaklistoffset: 0, + tp_iter: None, + tp_iternext: None, + tp_methods: null_mut(), + tp_members: null_mut(), + tp_getset: null_mut(), + tp_base: null_mut(), + tp_dict: null_mut(), + tp_descr_get: None, + tp_descr_set: None, + tp_dictoffset: 0, + tp_alloc: None, + #[cfg(Py_3_12)] + tp_watched: 0, + }); + let ob_ptr = Box::into_raw(ob); + PyType_Ready(ob_ptr); + ob_ptr + } } diff --git a/src/ffi/long.rs b/src/ffi/long.rs index 1ce944ed..7aa49a67 100644 --- a/src/ffi/long.rs +++ b/src/ffi/long.rs @@ -80,7 +80,7 @@ pub fn pylong_get_inline_value(ptr: *mut pyo3_ffi::PyObject) -> i64 { if pylong_is_unsigned(ptr) { (*(ptr as *mut PyLongObject)).long_value.ob_digit as i64 } else { - -1 * (*(ptr as *mut PyLongObject)).long_value.ob_digit as i64 + -((*(ptr as *mut PyLongObject)).long_value.ob_digit as i64) } } } diff --git a/src/ffi/yyjson.rs b/src/ffi/yyjson.rs index 73b958f5..c8440c07 100644 --- a/src/ffi/yyjson.rs +++ b/src/ffi/yyjson.rs @@ -18,7 +18,7 @@ pub struct yyjson_alc { >, pub ctx: *mut ::core::ffi::c_void, } -extern "C" { +unsafe extern "C" { pub fn yyjson_alc_pool_init( alc: *mut yyjson_alc, buf: *mut ::core::ffi::c_void, @@ -33,7 +33,7 @@ pub struct yyjson_read_err { pub msg: *const ::core::ffi::c_char, pub pos: usize, } -extern "C" { +unsafe extern "C" { pub fn yyjson_read_opts( dat: *mut ::core::ffi::c_char, len: usize, @@ -41,7 +41,7 @@ extern "C" { err: *mut yyjson_read_err, ) -> *mut yyjson_doc; } -extern "C" { +unsafe extern "C" { pub fn yyjson_doc_free(doc: *mut yyjson_doc); } #[repr(C)] diff --git a/src/lib.rs b/src/lib.rs index 64ace9e1..bcc5427a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![allow(unknown_lints)] // internal_features #![allow(unused_unsafe)] #![allow(clippy::missing_safety_doc)] +#![allow(clippy::needless_lifetimes)] #![allow(clippy::redundant_field_names)] #![allow(clippy::uninlined_format_args)] // MSRV 1.66 #![allow(clippy::upper_case_acronyms)] @@ -67,91 +68,94 @@ macro_rules! opt { } #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] pub unsafe extern "C" fn orjson_init_exec(mptr: *mut PyObject) -> c_int { - typeref::init_typerefs(); - { - let version = env!("CARGO_PKG_VERSION"); - let pyversion = - PyUnicode_FromStringAndSize(version.as_ptr() as *const c_char, version.len() as isize); - add!(mptr, "__version__\0", pyversion); - } - { - let dumps_doc = - "dumps(obj, /, default=None, option=None)\n--\n\nSerialize Python objects to JSON.\0"; - - let wrapped_dumps = PyMethodDef { - ml_name: "dumps\0".as_ptr() as *const c_char, - ml_meth: PyMethodDefPointer { - #[cfg(Py_3_10)] - PyCFunctionFastWithKeywords: dumps, - #[cfg(not(Py_3_10))] - _PyCFunctionFastWithKeywords: dumps, - }, - ml_flags: pyo3_ffi::METH_FASTCALL | METH_KEYWORDS, - ml_doc: dumps_doc.as_ptr() as *const c_char, - }; - - let func = PyCFunction_NewEx( - Box::into_raw(Box::new(wrapped_dumps)), - null_mut(), - PyUnicode_InternFromString("orjson\0".as_ptr() as *const c_char), - ); - add!(mptr, "dumps\0", func); - } + unsafe { + typeref::init_typerefs(); + { + let version = env!("CARGO_PKG_VERSION"); + let pyversion = PyUnicode_FromStringAndSize( + version.as_ptr() as *const c_char, + version.len() as isize, + ); + add!(mptr, "__version__\0", pyversion); + } + { + let dumps_doc = "dumps(obj, /, default=None, option=None)\n--\n\nSerialize Python objects to JSON.\0"; + + let wrapped_dumps = PyMethodDef { + ml_name: "dumps\0".as_ptr() as *const c_char, + ml_meth: PyMethodDefPointer { + #[cfg(Py_3_10)] + PyCFunctionFastWithKeywords: dumps, + #[cfg(not(Py_3_10))] + _PyCFunctionFastWithKeywords: dumps, + }, + ml_flags: pyo3_ffi::METH_FASTCALL | METH_KEYWORDS, + ml_doc: dumps_doc.as_ptr() as *const c_char, + }; + + let func = PyCFunction_NewEx( + Box::into_raw(Box::new(wrapped_dumps)), + null_mut(), + PyUnicode_InternFromString("orjson\0".as_ptr() as *const c_char), + ); + add!(mptr, "dumps\0", func); + } + + { + let loads_doc = "loads(obj, /)\n--\n\nDeserialize JSON to Python objects.\0"; + + let wrapped_loads = PyMethodDef { + ml_name: "loads\0".as_ptr() as *const c_char, + ml_meth: PyMethodDefPointer { PyCFunction: loads }, + ml_flags: METH_O, + ml_doc: loads_doc.as_ptr() as *const c_char, + }; + let func = PyCFunction_NewEx( + Box::into_raw(Box::new(wrapped_loads)), + null_mut(), + PyUnicode_InternFromString("orjson\0".as_ptr() as *const c_char), + ); + add!(mptr, "loads\0", func); + } - { - let loads_doc = "loads(obj, /)\n--\n\nDeserialize JSON to Python objects.\0"; - - let wrapped_loads = PyMethodDef { - ml_name: "loads\0".as_ptr() as *const c_char, - ml_meth: PyMethodDefPointer { PyCFunction: loads }, - ml_flags: METH_O, - ml_doc: loads_doc.as_ptr() as *const c_char, - }; - let func = PyCFunction_NewEx( - Box::into_raw(Box::new(wrapped_loads)), - null_mut(), - PyUnicode_InternFromString("orjson\0".as_ptr() as *const c_char), + add!(mptr, "Fragment\0", typeref::FRAGMENT_TYPE as *mut PyObject); + + opt!(mptr, "OPT_APPEND_NEWLINE\0", opt::APPEND_NEWLINE); + opt!(mptr, "OPT_INDENT_2\0", opt::INDENT_2); + opt!(mptr, "OPT_NAIVE_UTC\0", opt::NAIVE_UTC); + opt!(mptr, "OPT_NON_STR_KEYS\0", opt::NON_STR_KEYS); + opt!(mptr, "OPT_OMIT_MICROSECONDS\0", opt::OMIT_MICROSECONDS); + opt!( + mptr, + "OPT_PASSTHROUGH_DATACLASS\0", + opt::PASSTHROUGH_DATACLASS ); - add!(mptr, "loads\0", func); - } + opt!( + mptr, + "OPT_PASSTHROUGH_DATETIME\0", + opt::PASSTHROUGH_DATETIME + ); + opt!( + mptr, + "OPT_PASSTHROUGH_SUBCLASS\0", + opt::PASSTHROUGH_SUBCLASS + ); + opt!(mptr, "OPT_SERIALIZE_DATACLASS\0", opt::SERIALIZE_DATACLASS); + opt!(mptr, "OPT_SERIALIZE_NUMPY\0", opt::SERIALIZE_NUMPY); + opt!(mptr, "OPT_SERIALIZE_UUID\0", opt::SERIALIZE_UUID); + opt!(mptr, "OPT_SORT_KEYS\0", opt::SORT_KEYS); + opt!(mptr, "OPT_STRICT_INTEGER\0", opt::STRICT_INTEGER); + opt!(mptr, "OPT_UTC_Z\0", opt::UTC_Z); + + add!(mptr, "JSONDecodeError\0", typeref::JsonDecodeError); + add!(mptr, "JSONEncodeError\0", typeref::JsonEncodeError); - add!(mptr, "Fragment\0", typeref::FRAGMENT_TYPE as *mut PyObject); - - opt!(mptr, "OPT_APPEND_NEWLINE\0", opt::APPEND_NEWLINE); - opt!(mptr, "OPT_INDENT_2\0", opt::INDENT_2); - opt!(mptr, "OPT_NAIVE_UTC\0", opt::NAIVE_UTC); - opt!(mptr, "OPT_NON_STR_KEYS\0", opt::NON_STR_KEYS); - opt!(mptr, "OPT_OMIT_MICROSECONDS\0", opt::OMIT_MICROSECONDS); - opt!( - mptr, - "OPT_PASSTHROUGH_DATACLASS\0", - opt::PASSTHROUGH_DATACLASS - ); - opt!( - mptr, - "OPT_PASSTHROUGH_DATETIME\0", - opt::PASSTHROUGH_DATETIME - ); - opt!( - mptr, - "OPT_PASSTHROUGH_SUBCLASS\0", - opt::PASSTHROUGH_SUBCLASS - ); - opt!(mptr, "OPT_SERIALIZE_DATACLASS\0", opt::SERIALIZE_DATACLASS); - opt!(mptr, "OPT_SERIALIZE_NUMPY\0", opt::SERIALIZE_NUMPY); - opt!(mptr, "OPT_SERIALIZE_UUID\0", opt::SERIALIZE_UUID); - opt!(mptr, "OPT_SORT_KEYS\0", opt::SORT_KEYS); - opt!(mptr, "OPT_STRICT_INTEGER\0", opt::STRICT_INTEGER); - opt!(mptr, "OPT_UTC_Z\0", opt::UTC_Z); - - add!(mptr, "JSONDecodeError\0", typeref::JsonDecodeError); - add!(mptr, "JSONEncodeError\0", typeref::JsonEncodeError); - - 0 + 0 + } } #[cfg(Py_3_13)] @@ -172,45 +176,47 @@ const PYMODULEDEF_LEN: usize = 3; const PYMODULEDEF_LEN: usize = 4; #[allow(non_snake_case)] -#[no_mangle] +#[unsafe(no_mangle)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] pub unsafe extern "C" fn PyInit_orjson() -> *mut PyModuleDef { - let mod_slots: Box<[PyModuleDef_Slot; PYMODULEDEF_LEN]> = Box::new([ - PyModuleDef_Slot { - slot: Py_mod_exec, - value: orjson_init_exec as *mut c_void, - }, - #[cfg(Py_3_12)] - PyModuleDef_Slot { - slot: Py_mod_multiple_interpreters, - value: Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED, - }, - #[cfg(Py_3_13)] - PyModuleDef_Slot { - slot: Py_mod_gil, - value: Py_MOD_GIL_USED, - }, - PyModuleDef_Slot { - slot: 0, - value: null_mut(), - }, - ]); - - let init = Box::new(PyModuleDef { - m_base: PyModuleDef_HEAD_INIT, - m_name: "orjson\0".as_ptr() as *const c_char, - m_doc: null(), - m_size: 0, - m_methods: null_mut(), - m_slots: Box::into_raw(mod_slots) as *mut PyModuleDef_Slot, - m_traverse: None, - m_clear: None, - m_free: None, - }); - let init_ptr = Box::into_raw(init); - PyModuleDef_Init(init_ptr); - init_ptr + unsafe { + let mod_slots: Box<[PyModuleDef_Slot; PYMODULEDEF_LEN]> = Box::new([ + PyModuleDef_Slot { + slot: Py_mod_exec, + value: orjson_init_exec as *mut c_void, + }, + #[cfg(Py_3_12)] + PyModuleDef_Slot { + slot: Py_mod_multiple_interpreters, + value: Py_MOD_MULTIPLE_INTERPRETERS_NOT_SUPPORTED, + }, + #[cfg(Py_3_13)] + PyModuleDef_Slot { + slot: Py_mod_gil, + value: Py_MOD_GIL_USED, + }, + PyModuleDef_Slot { + slot: 0, + value: null_mut(), + }, + ]); + + let init = Box::new(PyModuleDef { + m_base: PyModuleDef_HEAD_INIT, + m_name: "orjson\0".as_ptr() as *const c_char, + m_doc: null(), + m_size: 0, + m_methods: null_mut(), + m_slots: Box::into_raw(mod_slots) as *mut PyModuleDef_Slot, + m_traverse: None, + m_clear: None, + m_free: None, + }); + let init_ptr = Box::into_raw(init); + ffi!(PyModuleDef_Init(init_ptr)); + init_ptr + } } #[cold] @@ -315,7 +321,7 @@ fn raise_dumps_exception_dynamic(err: &str) -> *mut PyObject { null_mut() } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn loads(_self: *mut PyObject, obj: *mut PyObject) -> *mut PyObject { match crate::deserialize::deserialize(obj) { Ok(val) => val.as_ptr(), @@ -323,66 +329,70 @@ pub unsafe extern "C" fn loads(_self: *mut PyObject, obj: *mut PyObject) -> *mut } } -#[no_mangle] +#[unsafe(no_mangle)] pub unsafe extern "C" fn dumps( _self: *mut PyObject, args: *const *mut PyObject, nargs: Py_ssize_t, kwnames: *mut PyObject, ) -> *mut PyObject { - let mut default: Option> = None; - let mut optsptr: Option> = None; - - let num_args = PyVectorcall_NARGS(nargs as usize); - if unlikely!(num_args == 0) { - return raise_dumps_exception_fixed( - "dumps() missing 1 required positional argument: 'obj'", - ); - } - if num_args & 2 == 2 { - default = Some(NonNull::new_unchecked(*args.offset(1))); - } - if num_args & 3 == 3 { - optsptr = Some(NonNull::new_unchecked(*args.offset(2))); - } - if unlikely!(!kwnames.is_null()) { - for i in 0..=Py_SIZE(kwnames).saturating_sub(1) { - let arg = PyTuple_GET_ITEM(kwnames, i as Py_ssize_t); - if arg == typeref::DEFAULT { - if unlikely!(num_args & 2 == 2) { - return raise_dumps_exception_fixed( - "dumps() got multiple values for argument: 'default'", - ); - } - default = Some(NonNull::new_unchecked(*args.offset(num_args + i))); - } else if arg == typeref::OPTION { - if unlikely!(num_args & 3 == 3) { + unsafe { + let mut default: Option> = None; + let mut optsptr: Option> = None; + + let num_args = PyVectorcall_NARGS(nargs as usize); + if unlikely!(num_args == 0) { + return raise_dumps_exception_fixed( + "dumps() missing 1 required positional argument: 'obj'", + ); + } + if num_args & 2 == 2 { + default = Some(NonNull::new_unchecked(*args.offset(1))); + } + if num_args & 3 == 3 { + optsptr = Some(NonNull::new_unchecked(*args.offset(2))); + } + if unlikely!(!kwnames.is_null()) { + for i in 0..=Py_SIZE(kwnames).saturating_sub(1) { + let arg = PyTuple_GET_ITEM(kwnames, i as Py_ssize_t); + if arg == typeref::DEFAULT { + if unlikely!(num_args & 2 == 2) { + return raise_dumps_exception_fixed( + "dumps() got multiple values for argument: 'default'", + ); + } + default = Some(NonNull::new_unchecked(*args.offset(num_args + i))); + } else if arg == typeref::OPTION { + if unlikely!(num_args & 3 == 3) { + return raise_dumps_exception_fixed( + "dumps() got multiple values for argument: 'option'", + ); + } + optsptr = Some(NonNull::new_unchecked(*args.offset(num_args + i))); + } else { return raise_dumps_exception_fixed( - "dumps() got multiple values for argument: 'option'", + "dumps() got an unexpected keyword argument", ); } - optsptr = Some(NonNull::new_unchecked(*args.offset(num_args + i))); - } else { - return raise_dumps_exception_fixed("dumps() got an unexpected keyword argument"); } } - } - let mut optsbits: i32 = 0; - if unlikely!(optsptr.is_some()) { - let opts = optsptr.unwrap(); - if (*opts.as_ptr()).ob_type == typeref::INT_TYPE { - optsbits = PyLong_AsLong(optsptr.unwrap().as_ptr()) as i32; - if unlikely!(!(0..=opt::MAX_OPT).contains(&optsbits)) { + let mut optsbits: i32 = 0; + if unlikely!(optsptr.is_some()) { + let opts = optsptr.unwrap(); + if (*opts.as_ptr()).ob_type == typeref::INT_TYPE { + optsbits = PyLong_AsLong(optsptr.unwrap().as_ptr()) as i32; + if unlikely!(!(0..=opt::MAX_OPT).contains(&optsbits)) { + return raise_dumps_exception_fixed("Invalid opts"); + } + } else if unlikely!(opts.as_ptr() != typeref::NONE) { return raise_dumps_exception_fixed("Invalid opts"); } - } else if unlikely!(opts.as_ptr() != typeref::NONE) { - return raise_dumps_exception_fixed("Invalid opts"); } - } - match crate::serialize::serialize(*args, default, optsbits as opt::Opt) { - Ok(val) => val.as_ptr(), - Err(err) => raise_dumps_exception_dynamic(err.as_str()), + match crate::serialize::serialize(*args, default, optsbits as opt::Opt) { + Ok(val) => val.as_ptr(), + Err(err) => raise_dumps_exception_dynamic(err.as_str()), + } } } diff --git a/src/serialize/error.rs b/src/serialize/error.rs index 744404be..f1329a30 100644 --- a/src/serialize/error.rs +++ b/src/serialize/error.rs @@ -27,14 +27,19 @@ impl std::fmt::Display for SerializeError { #[cfg_attr(feature = "optimize", optimize(size))] fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match *self { - SerializeError::DatetimeLibraryUnsupported => write!(f, "datetime's timezone library is not supported: use datetime.timezone.utc, pendulum, pytz, or dateutil"), + SerializeError::DatetimeLibraryUnsupported => write!( + f, + "datetime's timezone library is not supported: use datetime.timezone.utc, pendulum, pytz, or dateutil" + ), SerializeError::DefaultRecursionLimit => { write!(f, "default serializer exceeds recursion limit") } SerializeError::Integer53Bits => write!(f, "Integer exceeds 53-bit range"), SerializeError::Integer64Bits => write!(f, "Integer exceeds 64-bit range"), SerializeError::InvalidStr => write!(f, "{}", crate::util::INVALID_STR), - SerializeError::InvalidFragment => write!(f, "orjson.Fragment's content is not of type bytes or str"), + SerializeError::InvalidFragment => { + write!(f, "orjson.Fragment's content is not of type bytes or str") + } SerializeError::KeyMustBeStr => write!(f, "Dict key must be str"), SerializeError::RecursionLimit => write!(f, "Recursion limit reached"), SerializeError::TimeHasTzinfo => write!(f, "datetime.time must not have tzinfo set"), @@ -49,15 +54,15 @@ impl std::fmt::Display for SerializeError { f, "numpy array is not C contiguous; use ndarray.tolist() in default" ), - SerializeError::NumpyNotNativeEndian => write!( - f, - "numpy array is not native-endianness" - ), + SerializeError::NumpyNotNativeEndian => { + write!(f, "numpy array is not native-endianness") + } SerializeError::NumpyUnsupportedDatatype => { write!(f, "unsupported datatype in numpy array") } SerializeError::UnsupportedType(ptr) => { - let name = unsafe { CStr::from_ptr((*ob_type!(ptr.as_ptr())).tp_name).to_string_lossy() }; + let name = + unsafe { CStr::from_ptr((*ob_type!(ptr.as_ptr())).tp_name).to_string_lossy() }; write!(f, "Type is not JSON serializable: {}", name) } } diff --git a/src/serialize/per_type/datetimelike.rs b/src/serialize/per_type/datetimelike.rs index 6897a359..2e24479b 100644 --- a/src/serialize/per_type/datetimelike.rs +++ b/src/serialize/per_type/datetimelike.rs @@ -112,7 +112,7 @@ pub trait DateTimeLike { if opt_enabled!(opts, UTC_Z) { buf.push(b'Z'); } else { - buf.extend_from_slice(&[b'+', b'0', b'0', b':', b'0', b'0']); + buf.extend_from_slice(b"+00:00"); } } else { // This branch is only really hit by the Python datetime implementation, diff --git a/src/serialize/per_type/int.rs b/src/serialize/per_type/int.rs index d94fc3c3..75778cba 100644 --- a/src/serialize/per_type/int.rs +++ b/src/serialize/per_type/int.rs @@ -39,7 +39,7 @@ impl Serialize for IntSerializer { if is_signed == 0 { serializer.serialize_u64(crate::ffi::pylong_get_inline_value(self.ptr) as u64) } else { - serializer.serialize_i64(crate::ffi::pylong_get_inline_value(self.ptr) as i64) + serializer.serialize_i64(crate::ffi::pylong_get_inline_value(self.ptr)) } } else { let mut buffer: [u8; 8] = [0; 8]; diff --git a/src/serialize/writer/str/avx512.rs b/src/serialize/writer/str/avx512.rs index 1be47623..983d4a30 100644 --- a/src/serialize/writer/str/avx512.rs +++ b/src/serialize/writer/str/avx512.rs @@ -99,18 +99,20 @@ pub unsafe fn format_escaped_str_impl_512vl( value_ptr: *const u8, value_len: usize, ) -> usize { - const STRIDE: usize = 32; + unsafe { + const STRIDE: usize = 32; - let mut dst = odst; - let mut src = value_ptr; + let mut dst = odst; + let mut src = value_ptr; - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - impl_format_simd_avx512vl!(dst, src, value_len); + impl_format_simd_avx512vl!(dst, src, value_len); - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - dst as usize - odst as usize + dst as usize - odst as usize + } } diff --git a/src/serialize/writer/str/generic.rs b/src/serialize/writer/str/generic.rs index 0ca500f0..e7973f2a 100644 --- a/src/serialize/writer/str/generic.rs +++ b/src/serialize/writer/str/generic.rs @@ -87,23 +87,25 @@ pub unsafe fn format_escaped_str_impl_generic_128( value_ptr: *const u8, value_len: usize, ) -> usize { - const STRIDE: usize = 16; - type StrVector = core::simd::u8x16; + unsafe { + const STRIDE: usize = 16; + type StrVector = core::simd::u8x16; - let mut dst = odst; - let mut src = value_ptr; + let mut dst = odst; + let mut src = value_ptr; - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - if value_len < STRIDE { - impl_format_scalar!(dst, src, value_len) - } else { - impl_format_simd_generic_128!(dst, src, value_len); - } + if value_len < STRIDE { + impl_format_scalar!(dst, src, value_len) + } else { + impl_format_simd_generic_128!(dst, src, value_len); + } - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - dst as usize - odst as usize + dst as usize - odst as usize + } } diff --git a/src/serialize/writer/str/sse2.rs b/src/serialize/writer/str/sse2.rs index 45114e0c..43def30a 100644 --- a/src/serialize/writer/str/sse2.rs +++ b/src/serialize/writer/str/sse2.rs @@ -106,22 +106,24 @@ pub unsafe fn format_escaped_str_impl_sse2_128( value_ptr: *const u8, value_len: usize, ) -> usize { - const STRIDE: usize = 16; + unsafe { + const STRIDE: usize = 16; - let mut dst = odst; - let mut src = value_ptr; + let mut dst = odst; + let mut src = value_ptr; - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - if value_len < STRIDE { - impl_format_scalar!(dst, src, value_len) - } else { - impl_format_simd_sse2_128!(dst, src, value_len); - } + if value_len < STRIDE { + impl_format_scalar!(dst, src, value_len) + } else { + impl_format_simd_sse2_128!(dst, src, value_len); + } - core::ptr::write(dst, b'"'); - dst = dst.add(1); + core::ptr::write(dst, b'"'); + dst = dst.add(1); - dst as usize - odst as usize + dst as usize - odst as usize + } } diff --git a/src/typeref.rs b/src/typeref.rs index 0fe13f9f..f9c15e37 100644 --- a/src/typeref.rs +++ b/src/typeref.rs @@ -205,27 +205,32 @@ fn _init_typerefs_impl() -> bool { #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_json_exc() -> *mut PyObject { - let module = PyImport_ImportModule("json\0".as_ptr() as *const c_char); - let module_dict = PyObject_GenericGetDict(module, null_mut()); - let ptr = PyMapping_GetItemString(module_dict, "JSONDecodeError\0".as_ptr() as *const c_char); - let res = pyo3_ffi::PyErr_NewException( - "orjson.JSONDecodeError\0".as_ptr() as *const c_char, - ptr, - null_mut(), - ); - Py_DECREF(ptr); - Py_DECREF(module_dict); - Py_DECREF(module); - Py_INCREF(res); - res + unsafe { + let module = PyImport_ImportModule("json\0".as_ptr() as *const c_char); + let module_dict = PyObject_GenericGetDict(module, null_mut()); + let ptr = + PyMapping_GetItemString(module_dict, "JSONDecodeError\0".as_ptr() as *const c_char); + let res = pyo3_ffi::PyErr_NewException( + "orjson.JSONDecodeError\0".as_ptr() as *const c_char, + ptr, + null_mut(), + ); + Py_DECREF(ptr); + Py_DECREF(module_dict); + Py_DECREF(module); + Py_INCREF(res); + res + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_numpy_type(numpy_module_dict: *mut PyObject, np_type: &str) -> *mut PyTypeObject { - let ptr = PyMapping_GetItemString(numpy_module_dict, np_type.as_ptr() as *const c_char); - Py_XDECREF(ptr); - ptr as *mut PyTypeObject + unsafe { + let ptr = PyMapping_GetItemString(numpy_module_dict, np_type.as_ptr() as *const c_char); + Py_XDECREF(ptr); + ptr as *mut PyTypeObject + } } #[cold] @@ -263,86 +268,102 @@ pub fn load_numpy_types() -> Box>> { #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_field_type() -> *mut PyTypeObject { - let module = PyImport_ImportModule("dataclasses\0".as_ptr() as *const c_char); - let module_dict = PyObject_GenericGetDict(module, null_mut()); - let ptr = PyMapping_GetItemString(module_dict, "_FIELD\0".as_ptr() as *const c_char) - as *mut PyTypeObject; - Py_DECREF(module_dict); - Py_DECREF(module); - ptr + unsafe { + let module = PyImport_ImportModule("dataclasses\0".as_ptr() as *const c_char); + let module_dict = PyObject_GenericGetDict(module, null_mut()); + let ptr = PyMapping_GetItemString(module_dict, "_FIELD\0".as_ptr() as *const c_char) + as *mut PyTypeObject; + Py_DECREF(module_dict); + Py_DECREF(module); + ptr + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_enum_type() -> *mut PyTypeObject { - let module = PyImport_ImportModule("enum\0".as_ptr() as *const c_char); - let module_dict = PyObject_GenericGetDict(module, null_mut()); - let ptr = PyMapping_GetItemString(module_dict, "EnumMeta\0".as_ptr() as *const c_char) - as *mut PyTypeObject; - Py_DECREF(module_dict); - Py_DECREF(module); - ptr + unsafe { + let module = PyImport_ImportModule("enum\0".as_ptr() as *const c_char); + let module_dict = PyObject_GenericGetDict(module, null_mut()); + let ptr = PyMapping_GetItemString(module_dict, "EnumMeta\0".as_ptr() as *const c_char) + as *mut PyTypeObject; + Py_DECREF(module_dict); + Py_DECREF(module); + ptr + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_uuid_type() -> *mut PyTypeObject { - let uuid_mod = PyImport_ImportModule("uuid\0".as_ptr() as *const c_char); - let uuid_mod_dict = PyObject_GenericGetDict(uuid_mod, null_mut()); - let uuid = PyMapping_GetItemString(uuid_mod_dict, "NAMESPACE_DNS\0".as_ptr() as *const c_char); - let ptr = (*uuid).ob_type; - Py_DECREF(uuid); - Py_DECREF(uuid_mod_dict); - Py_DECREF(uuid_mod); - ptr + unsafe { + let uuid_mod = PyImport_ImportModule("uuid\0".as_ptr() as *const c_char); + let uuid_mod_dict = PyObject_GenericGetDict(uuid_mod, null_mut()); + let uuid = + PyMapping_GetItemString(uuid_mod_dict, "NAMESPACE_DNS\0".as_ptr() as *const c_char); + let ptr = (*uuid).ob_type; + Py_DECREF(uuid); + Py_DECREF(uuid_mod_dict); + Py_DECREF(uuid_mod); + ptr + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_datetime_type() -> *mut PyTypeObject { - let datetime = ((*PyDateTimeAPI()).DateTime_FromDateAndTime)( - 1970, - 1, - 1, - 0, - 0, - 0, - 0, - NONE, - (*(PyDateTimeAPI())).DateTimeType, - ); - let ptr = (*datetime).ob_type; - Py_DECREF(datetime); - ptr + unsafe { + let datetime = ((*PyDateTimeAPI()).DateTime_FromDateAndTime)( + 1970, + 1, + 1, + 0, + 0, + 0, + 0, + NONE, + (*(PyDateTimeAPI())).DateTimeType, + ); + let ptr = (*datetime).ob_type; + Py_DECREF(datetime); + ptr + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_date_type() -> *mut PyTypeObject { - let date = ((*PyDateTimeAPI()).Date_FromDate)(1, 1, 1, (*(PyDateTimeAPI())).DateType); - let ptr = (*date).ob_type; - Py_DECREF(date); - ptr + unsafe { + let date = ((*PyDateTimeAPI()).Date_FromDate)(1, 1, 1, (*(PyDateTimeAPI())).DateType); + let ptr = (*date).ob_type; + Py_DECREF(date); + ptr + } } #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_time_type() -> *mut PyTypeObject { - let time = ((*PyDateTimeAPI()).Time_FromTime)(0, 0, 0, 0, NONE, (*(PyDateTimeAPI())).TimeType); - let ptr = (*time).ob_type; - Py_DECREF(time); - ptr + unsafe { + let time = + ((*PyDateTimeAPI()).Time_FromTime)(0, 0, 0, 0, NONE, (*(PyDateTimeAPI())).TimeType); + let ptr = (*time).ob_type; + Py_DECREF(time); + ptr + } } #[cfg(Py_3_9)] #[cold] #[cfg_attr(feature = "optimize", optimize(size))] unsafe fn look_up_zoneinfo_type() -> *mut PyTypeObject { - let module = PyImport_ImportModule("zoneinfo\0".as_ptr() as *const c_char); - let module_dict = PyObject_GenericGetDict(module, null_mut()); - let ptr = PyMapping_GetItemString(module_dict, "ZoneInfo\0".as_ptr() as *const c_char) - as *mut PyTypeObject; - Py_DECREF(module_dict); - Py_DECREF(module); - ptr + unsafe { + let module = PyImport_ImportModule("zoneinfo\0".as_ptr() as *const c_char); + let module_dict = PyObject_GenericGetDict(module, null_mut()); + let ptr = PyMapping_GetItemString(module_dict, "ZoneInfo\0".as_ptr() as *const c_char) + as *mut PyTypeObject; + Py_DECREF(module_dict); + Py_DECREF(module); + ptr + } }