Skip to content

Commit d860078

Browse files
committed
PyRef idiom refactors
1 parent 343ae2f commit d860078

30 files changed

+1257
-534
lines changed

src/deserialize/backend/yyjson.rs

Lines changed: 36 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@ use super::ffi::{
66
yyjson_read_opts, yyjson_val,
77
};
88
use crate::deserialize::DeserializeError;
9-
use crate::deserialize::pyobject::{
10-
get_unicode_key, parse_f64, parse_false, parse_i64, parse_none, parse_true, parse_u64,
11-
};
12-
use crate::ffi::PyStrRef;
13-
use crate::util::usize_to_isize;
9+
use crate::deserialize::pyobject::get_unicode_key;
10+
use crate::ffi::{PyBoolRef, PyDictRef, PyFloatRef, PyIntRef, PyListRef, PyNoneRef, PyStrRef};
1411
use core::ffi::c_char;
1512
use core::ptr::{NonNull, null, null_mut};
1613
use std::borrow::Cow;
@@ -119,25 +116,23 @@ pub(crate) fn deserialize(
119116
ElementType::Uint64 => parse_yy_u64(val),
120117
ElementType::Int64 => parse_yy_i64(val),
121118
ElementType::Double => parse_yy_f64(val),
122-
ElementType::Null => parse_none(),
123-
ElementType::True => parse_true(),
124-
ElementType::False => parse_false(),
119+
ElementType::Null => PyNoneRef::none().as_non_null_ptr(),
120+
ElementType::True => PyBoolRef::pytrue().as_non_null_ptr(),
121+
ElementType::False => PyBoolRef::pyfalse().as_non_null_ptr(),
125122
ElementType::Array | ElementType::Object => unreachable_unchecked!(),
126123
}
127124
} else if is_yyjson_tag!(val, TAG_ARRAY) {
128-
let pyval = nonnull!(ffi!(PyList_New(usize_to_isize(unsafe_yyjson_get_len(val)))));
125+
let pyval = PyListRef::with_capacity(unsafe_yyjson_get_len(val));
129126
if unsafe_yyjson_get_len(val) > 0 {
130-
populate_yy_array(pyval.as_ptr(), val);
127+
populate_yy_array(pyval.clone(), val);
131128
}
132-
pyval
129+
pyval.as_non_null_ptr()
133130
} else {
134-
let pyval = nonnull!(ffi!(_PyDict_NewPresized(usize_to_isize(
135-
unsafe_yyjson_get_len(val)
136-
))));
131+
let pyval = PyDictRef::with_capacity(unsafe_yyjson_get_len(val));
137132
if unsafe_yyjson_get_len(val) > 0 {
138-
populate_yy_object(pyval.as_ptr(), val);
133+
populate_yy_object(pyval.clone(), val);
139134
}
140-
pyval
135+
pyval.as_non_null_ptr()
141136
}
142137
};
143138
ffi!(PyMem_Free(buffer_ptr));
@@ -184,54 +179,42 @@ fn parse_yy_string(elem: *mut yyjson_val) -> NonNull<crate::ffi::PyObject> {
184179

185180
#[inline(always)]
186181
fn parse_yy_u64(elem: *mut yyjson_val) -> NonNull<crate::ffi::PyObject> {
187-
parse_u64(unsafe { (*elem).uni.u64_ })
182+
PyIntRef::from_u64(unsafe { (*elem).uni.u64_ }).as_non_null_ptr()
188183
}
189184

190185
#[inline(always)]
191186
fn parse_yy_i64(elem: *mut yyjson_val) -> NonNull<crate::ffi::PyObject> {
192-
parse_i64(unsafe { (*elem).uni.i64_ })
187+
PyIntRef::from_i64(unsafe { (*elem).uni.i64_ }).as_non_null_ptr()
193188
}
194189

195190
#[inline(always)]
196191
fn parse_yy_f64(elem: *mut yyjson_val) -> NonNull<crate::ffi::PyObject> {
197-
parse_f64(unsafe { (*elem).uni.f64_ })
198-
}
199-
200-
macro_rules! append_to_list {
201-
($dptr:expr, $pyval:expr) => {
202-
unsafe {
203-
core::ptr::write($dptr, $pyval);
204-
$dptr = $dptr.add(1);
205-
}
206-
};
192+
PyFloatRef::from_f64(unsafe { (*elem).uni.f64_ }).as_non_null_ptr()
207193
}
208194

209195
#[inline(never)]
210-
fn populate_yy_array(list: *mut crate::ffi::PyObject, elem: *mut yyjson_val) {
196+
fn populate_yy_array(mut list: PyListRef, elem: *mut yyjson_val) {
211197
unsafe {
212198
let len = unsafe_yyjson_get_len(elem);
213199
assume!(len >= 1);
214200
let mut next = unsafe_yyjson_get_first(elem);
215-
let mut dptr = (*list.cast::<crate::ffi::PyListObject>()).ob_item;
216201

217-
for _ in 0..len {
202+
for idx in 0..len {
218203
let val = next;
219204
if unsafe_yyjson_is_ctn(val) {
220205
cold_path!();
221206
next = unsafe_yyjson_get_next_container(val);
222207
if is_yyjson_tag!(val, TAG_ARRAY) {
223-
let pyval = ffi!(PyList_New(usize_to_isize(unsafe_yyjson_get_len(val))));
224-
append_to_list!(dptr, pyval);
208+
let pyval = PyListRef::with_capacity(unsafe_yyjson_get_len(val));
209+
list.set(idx, pyval.as_ptr());
225210
if unsafe_yyjson_get_len(val) > 0 {
226-
populate_yy_array(pyval, val);
211+
populate_yy_array(pyval.clone(), val);
227212
}
228213
} else {
229-
let pyval = ffi!(_PyDict_NewPresized(usize_to_isize(unsafe_yyjson_get_len(
230-
val
231-
))));
232-
append_to_list!(dptr, pyval);
214+
let pyval = PyDictRef::with_capacity(unsafe_yyjson_get_len(val));
215+
list.set(idx, pyval.as_ptr());
233216
if unsafe_yyjson_get_len(val) > 0 {
234-
populate_yy_object(pyval, val);
217+
populate_yy_object(pyval.clone(), val);
235218
}
236219
}
237220
} else {
@@ -241,19 +224,19 @@ fn populate_yy_array(list: *mut crate::ffi::PyObject, elem: *mut yyjson_val) {
241224
ElementType::Uint64 => parse_yy_u64(val),
242225
ElementType::Int64 => parse_yy_i64(val),
243226
ElementType::Double => parse_yy_f64(val),
244-
ElementType::Null => parse_none(),
245-
ElementType::True => parse_true(),
246-
ElementType::False => parse_false(),
227+
ElementType::Null => PyNoneRef::none().as_non_null_ptr(),
228+
ElementType::True => PyBoolRef::pytrue().as_non_null_ptr(),
229+
ElementType::False => PyBoolRef::pyfalse().as_non_null_ptr(),
247230
ElementType::Array | ElementType::Object => unreachable_unchecked!(),
248231
};
249-
append_to_list!(dptr, pyval.as_ptr());
232+
list.set(idx, pyval.as_ptr());
250233
}
251234
}
252235
}
253236
}
254237

255238
#[inline(never)]
256-
fn populate_yy_object(dict: *mut crate::ffi::PyObject, elem: *mut yyjson_val) {
239+
fn populate_yy_object(mut dict: PyDictRef, elem: *mut yyjson_val) {
257240
unsafe {
258241
let len = unsafe_yyjson_get_len(elem);
259242
assume!(len >= 1);
@@ -273,18 +256,16 @@ fn populate_yy_object(dict: *mut crate::ffi::PyObject, elem: *mut yyjson_val) {
273256
next_key = unsafe_yyjson_get_next_container(val);
274257
next_val = next_key.add(1);
275258
if is_yyjson_tag!(val, TAG_ARRAY) {
276-
let pyval = ffi!(PyList_New(usize_to_isize(unsafe_yyjson_get_len(val))));
277-
pydict_setitem!(dict, pykey.as_ptr(), pyval);
259+
let pyval = PyListRef::with_capacity(unsafe_yyjson_get_len(val));
260+
dict.set(pykey, pyval.as_ptr());
278261
if unsafe_yyjson_get_len(val) > 0 {
279262
populate_yy_array(pyval, val);
280263
}
281264
} else {
282-
let pyval = ffi!(_PyDict_NewPresized(usize_to_isize(unsafe_yyjson_get_len(
283-
val
284-
))));
285-
pydict_setitem!(dict, pykey.as_ptr(), pyval);
265+
let pyval = PyDictRef::with_capacity(unsafe_yyjson_get_len(val));
266+
dict.set(pykey, pyval.as_ptr());
286267
if unsafe_yyjson_get_len(val) > 0 {
287-
populate_yy_object(pyval, val);
268+
populate_yy_object(pyval.clone(), val);
288269
}
289270
}
290271
} else {
@@ -295,12 +276,12 @@ fn populate_yy_object(dict: *mut crate::ffi::PyObject, elem: *mut yyjson_val) {
295276
ElementType::Uint64 => parse_yy_u64(val),
296277
ElementType::Int64 => parse_yy_i64(val),
297278
ElementType::Double => parse_yy_f64(val),
298-
ElementType::Null => parse_none(),
299-
ElementType::True => parse_true(),
300-
ElementType::False => parse_false(),
279+
ElementType::Null => PyNoneRef::none().as_non_null_ptr(),
280+
ElementType::True => PyBoolRef::pytrue().as_non_null_ptr(),
281+
ElementType::False => PyBoolRef::pyfalse().as_non_null_ptr(),
301282
ElementType::Array | ElementType::Object => unreachable_unchecked!(),
302283
};
303-
pydict_setitem!(dict, pykey.as_ptr(), pyval.as_ptr());
284+
dict.set(pykey, pyval.as_ptr());
304285
}
305286
}
306287
}

src/deserialize/pyobject.rs

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22
// Copyright ijl (2022-2026)
33

44
use crate::ffi::PyStrRef;
5-
use crate::typeref::{FALSE, NONE, TRUE};
6-
use core::ptr::NonNull;
75

86
#[cfg(all(CPython, not(Py_GIL_DISABLED)))]
97
#[inline(always)]
@@ -43,38 +41,3 @@ pub(crate) fn get_unicode_key(key_str: &str) -> PyStrRef {
4341
pub(crate) fn get_unicode_key(key_str: &str) -> PyStrRef {
4442
PyStrRef::from_str(key_str)
4543
}
46-
47-
#[allow(dead_code)]
48-
#[inline(always)]
49-
pub(crate) fn parse_bool(val: bool) -> NonNull<crate::ffi::PyObject> {
50-
if val { parse_true() } else { parse_false() }
51-
}
52-
53-
#[inline(always)]
54-
pub(crate) fn parse_true() -> NonNull<crate::ffi::PyObject> {
55-
nonnull!(use_immortal!(TRUE))
56-
}
57-
58-
#[inline(always)]
59-
pub(crate) fn parse_false() -> NonNull<crate::ffi::PyObject> {
60-
nonnull!(use_immortal!(FALSE))
61-
}
62-
#[inline(always)]
63-
pub(crate) fn parse_i64(val: i64) -> NonNull<crate::ffi::PyObject> {
64-
nonnull!(ffi!(PyLong_FromLongLong(val)))
65-
}
66-
67-
#[inline(always)]
68-
pub(crate) fn parse_u64(val: u64) -> NonNull<crate::ffi::PyObject> {
69-
nonnull!(ffi!(PyLong_FromUnsignedLongLong(val)))
70-
}
71-
72-
#[inline(always)]
73-
pub(crate) fn parse_f64(val: f64) -> NonNull<crate::ffi::PyObject> {
74-
nonnull!(ffi!(PyFloat_FromDouble(val)))
75-
}
76-
77-
#[inline(always)]
78-
pub(crate) fn parse_none() -> NonNull<crate::ffi::PyObject> {
79-
nonnull!(use_immortal!(NONE))
80-
}

src/exception.rs

Lines changed: 23 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,29 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2-
// Copyright ijl (2020-2025), Jack Amadeo (2023)
2+
// Copyright ijl (2020-2026), Jack Amadeo (2023)
33

4-
use core::ffi::c_char;
54
use core::ptr::null_mut;
65

76
use crate::deserialize::DeserializeError;
8-
use crate::ffi::{
9-
Py_DECREF, PyErr_SetObject, PyLong_FromLongLong, PyObject, PyTuple_New,
10-
PyUnicode_FromStringAndSize,
11-
};
12-
use crate::typeref::{EMPTY_UNICODE, JsonDecodeError, JsonEncodeError};
13-
use crate::util::usize_to_isize;
7+
use crate::ffi::{Py_DECREF, PyErr_SetObject, PyIntRef, PyObject, PyStrRef, PyTupleRef};
8+
use crate::typeref::{JsonDecodeError, JsonEncodeError};
149

1510
#[cold]
1611
#[inline(never)]
1712
#[cfg_attr(feature = "optimize", optimize(size))]
1813
pub(crate) fn raise_loads_exception(err: DeserializeError) -> *mut PyObject {
1914
unsafe {
20-
let err_pos = err.pos();
21-
let msg = err.message;
15+
let err_pos = PyIntRef::from_i64(err.pos());
16+
let err_msg = PyStrRef::from_str(&err.message);
2217
let doc = match err.data {
23-
Some(as_str) => PyUnicode_FromStringAndSize(
24-
as_str.as_ptr().cast::<c_char>(),
25-
usize_to_isize(as_str.len()),
26-
),
27-
None => {
28-
use_immortal!(EMPTY_UNICODE)
29-
}
18+
Some(as_str) => PyStrRef::from_str(as_str),
19+
None => PyStrRef::empty(),
3020
};
31-
let err_msg =
32-
PyUnicode_FromStringAndSize(msg.as_ptr().cast::<c_char>(), usize_to_isize(msg.len()));
33-
let args = PyTuple_New(3);
34-
let pos = PyLong_FromLongLong(err_pos);
35-
crate::ffi::PyTuple_SET_ITEM(args, 0, err_msg);
36-
crate::ffi::PyTuple_SET_ITEM(args, 1, doc);
37-
crate::ffi::PyTuple_SET_ITEM(args, 2, pos);
38-
PyErr_SetObject(JsonDecodeError, args);
39-
Py_DECREF(args);
21+
let mut args = PyTupleRef::with_capacity(3);
22+
args.set(0, err_msg.as_ptr());
23+
args.set(1, doc.as_ptr());
24+
args.set(2, err_pos.as_ptr());
25+
PyErr_SetObject(JsonDecodeError, args.as_ptr());
26+
Py_DECREF(args.as_ptr());
4027
}
4128
null_mut()
4229
}
@@ -46,11 +33,9 @@ pub(crate) fn raise_loads_exception(err: DeserializeError) -> *mut PyObject {
4633
#[cfg_attr(feature = "optimize", optimize(size))]
4734
pub(crate) fn raise_dumps_exception_fixed(msg: &str) -> *mut PyObject {
4835
unsafe {
49-
let err_msg =
50-
PyUnicode_FromStringAndSize(msg.as_ptr().cast::<c_char>(), usize_to_isize(msg.len()));
51-
PyErr_SetObject(JsonEncodeError, err_msg);
52-
debug_assert!(ffi!(Py_REFCNT(err_msg)) <= 2);
53-
Py_DECREF(err_msg);
36+
let err_msg = PyStrRef::from_str(msg);
37+
PyErr_SetObject(JsonEncodeError, err_msg.as_ptr());
38+
Py_DECREF(err_msg.as_ptr());
5439
}
5540
null_mut()
5641
}
@@ -63,11 +48,9 @@ pub(crate) fn raise_dumps_exception_dynamic(err: &str) -> *mut PyObject {
6348
unsafe {
6449
let cause_exc: *mut PyObject = crate::ffi::PyErr_GetRaisedException();
6550

66-
let err_msg =
67-
PyUnicode_FromStringAndSize(err.as_ptr().cast::<c_char>(), usize_to_isize(err.len()));
68-
PyErr_SetObject(JsonEncodeError, err_msg);
69-
debug_assert!(ffi!(Py_REFCNT(err_msg)) <= 2);
70-
Py_DECREF(err_msg);
51+
let err_msg = PyStrRef::from_str(err);
52+
PyErr_SetObject(JsonEncodeError, err_msg.as_ptr());
53+
Py_DECREF(err_msg.as_ptr());
7154

7255
if !cause_exc.is_null() {
7356
let exc: *mut PyObject = crate::ffi::PyErr_GetRaisedException();
@@ -89,11 +72,10 @@ pub(crate) fn raise_dumps_exception_dynamic(err: &str) -> *mut PyObject {
8972
let mut cause_traceback: *mut PyObject = null_mut();
9073
crate::ffi::PyErr_Fetch(&mut cause_tp, &mut cause_val, &mut cause_traceback);
9174

92-
let err_msg =
93-
PyUnicode_FromStringAndSize(err.as_ptr().cast::<c_char>(), usize_to_isize(err.len()));
94-
PyErr_SetObject(JsonEncodeError, err_msg);
95-
debug_assert!(ffi!(Py_REFCNT(err_msg)) == 2);
96-
Py_DECREF(err_msg);
75+
let err_msg = PyStrRef::from_str(err);
76+
PyErr_SetObject(JsonEncodeError, err_msg.as_ptr());
77+
Py_DECREF(err_msg.as_ptr());
78+
9779
let mut tp: *mut PyObject = null_mut();
9880
let mut val: *mut PyObject = null_mut();
9981
let mut traceback: *mut PyObject = null_mut();

src/ffi/bytes.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ pub(crate) unsafe fn PyBytes_AS_STRING(op: *mut PyObject) -> *const c_char {
2323
#[allow(non_snake_case)]
2424
#[inline(always)]
2525
pub(crate) unsafe fn PyBytes_GET_SIZE(op: *mut PyObject) -> Py_ssize_t {
26-
unsafe { super::compat::Py_SIZE(op.cast::<crate::ffi::PyVarObject>()) }
26+
unsafe { super::compat::Py_SIZE(op) }
2727
}

src/ffi/compat.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,15 @@ pub(crate) unsafe fn PyLong_AsByteArray(
122122
#[cfg(CPython)]
123123
#[inline(always)]
124124
#[allow(non_snake_case)]
125-
pub(crate) unsafe fn Py_SIZE(op: *mut pyo3_ffi::PyVarObject) -> pyo3_ffi::Py_ssize_t {
126-
unsafe { (*op).ob_size }
125+
pub(crate) unsafe fn Py_SIZE(op: *mut pyo3_ffi::PyObject) -> pyo3_ffi::Py_ssize_t {
126+
unsafe { (*op.cast::<pyo3_ffi::PyVarObject>()).ob_size }
127127
}
128128

129129
#[cfg(not(CPython))]
130130
#[inline(always)]
131131
#[allow(non_snake_case)]
132-
pub(crate) unsafe fn Py_SIZE(op: *mut pyo3_ffi::PyVarObject) -> pyo3_ffi::Py_ssize_t {
133-
unsafe { pyo3_ffi::Py_SIZE(op.cast::<pyo3_ffi::PyObject>()) }
132+
pub(crate) unsafe fn Py_SIZE(op: *mut pyo3_ffi::PyObject) -> pyo3_ffi::Py_ssize_t {
133+
unsafe { pyo3_ffi::Py_SIZE(op) }
134134
}
135135

136136
#[allow(unused)]
@@ -156,7 +156,12 @@ pub(crate) unsafe fn PyTuple_GET_ITEM(
156156
op: *mut pyo3_ffi::PyObject,
157157
i: pyo3_ffi::Py_ssize_t,
158158
) -> *mut pyo3_ffi::PyObject {
159-
unsafe { pyo3_ffi::PyTuple_GET_ITEM(op, i) }
159+
unsafe {
160+
*(*op.cast::<pyo3_ffi::PyTupleObject>())
161+
.ob_item
162+
.as_ptr()
163+
.offset(i)
164+
}
160165
}
161166

162167
#[cfg(not(CPython))]
@@ -177,7 +182,12 @@ pub(crate) unsafe fn PyTuple_SET_ITEM(
177182
i: pyo3_ffi::Py_ssize_t,
178183
v: *mut pyo3_ffi::PyObject,
179184
) {
180-
unsafe { pyo3_ffi::PyTuple_SET_ITEM(op, i, v) }
185+
unsafe {
186+
*(*(op.cast::<pyo3_ffi::PyTupleObject>()))
187+
.ob_item
188+
.as_mut_ptr()
189+
.offset(i) = v;
190+
}
181191
}
182192

183193
#[cfg(not(CPython))]

0 commit comments

Comments
 (0)