Skip to content

Commit 71e0516

Browse files
committed
PyStrRef
1 parent 1096df4 commit 71e0516

File tree

23 files changed

+473
-357
lines changed

23 files changed

+473
-357
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ avx512 = []
3838
cold_path = []
3939
generic_simd = []
4040
inline_int = []
41+
inline_str = []
4142
optimize = []
4243

4344
[dependencies]

build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ fn main() {
1717
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
1818
if is_64_bit_python {
1919
println!("cargo:rustc-cfg=feature=\"inline_int\"");
20+
#[cfg(target_endian = "little")]
21+
println!("cargo:rustc-cfg=feature=\"inline_str\"");
2022
}
2123
}
2224
pyo3_build_config::PythonImplementation::GraalPy => not_supported("GraalPy"),

src/deserialize/backend/yyjson.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2-
// Copyright ijl (2022-2025), Anders Kaseorg (2023)
2+
// Copyright ijl (2022-2026), Anders Kaseorg (2023)
33

44
use super::ffi::{
55
YYJSON_READ_SUCCESS, yyjson_alc, yyjson_alc_pool_init, yyjson_doc, yyjson_read_err,
@@ -9,7 +9,7 @@ use crate::deserialize::DeserializeError;
99
use crate::deserialize::pyobject::{
1010
get_unicode_key, parse_f64, parse_false, parse_i64, parse_none, parse_true, parse_u64,
1111
};
12-
use crate::str::PyStr;
12+
use crate::ffi::PyStrRef;
1313
use crate::util::usize_to_isize;
1414
use core::ffi::c_char;
1515
use core::ptr::{NonNull, null, null_mut};
@@ -175,7 +175,7 @@ impl ElementType {
175175

176176
#[inline(always)]
177177
fn parse_yy_string(elem: *mut yyjson_val) -> NonNull<crate::ffi::PyObject> {
178-
PyStr::from_str(str_from_slice!(
178+
PyStrRef::from_str(str_from_slice!(
179179
(*elem).uni.str_.cast::<u8>(),
180180
unsafe_yyjson_get_len(elem)
181181
))

src/deserialize/cache.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,27 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright ijl (2019-2025)
2+
// Copyright ijl (2019-2026)
33

4-
use crate::str::PyStr;
4+
use crate::ffi::PyStrRef;
55
use associative_cache::{AssociativeCache, Capacity2048, HashDirectMapped, RoundRobinReplacement};
66
use core::cell::OnceCell;
77

88
#[repr(transparent)]
99
pub(crate) struct CachedKey {
10-
ptr: PyStr,
10+
ptr: PyStrRef,
1111
}
1212

1313
unsafe impl Send for CachedKey {}
1414
unsafe impl Sync for CachedKey {}
1515

1616
impl CachedKey {
17-
pub fn new(ptr: PyStr) -> CachedKey {
17+
pub fn new(ptr: PyStrRef) -> CachedKey {
1818
CachedKey { ptr: ptr }
1919
}
20-
pub fn get(&mut self) -> PyStr {
20+
pub fn get(&mut self) -> PyStrRef {
2121
let ptr = self.ptr.as_ptr();
2222
debug_assert!(ffi!(Py_REFCNT(ptr)) >= 1);
2323
ffi!(Py_INCREF(ptr));
24-
self.ptr
24+
self.ptr.clone()
2525
}
2626
}
2727

src/deserialize/pyobject.rs

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,47 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright ijl (2022-2025)
2+
// Copyright ijl (2022-2026)
33

4-
#[cfg(not(Py_GIL_DISABLED))]
5-
use crate::deserialize::cache::{CachedKey, KEY_MAP};
6-
use crate::str::PyStr;
4+
use crate::ffi::PyStrRef;
75
use crate::typeref::{FALSE, NONE, TRUE};
86
use core::ptr::NonNull;
97

10-
#[cfg(not(Py_GIL_DISABLED))]
8+
#[cfg(all(CPython, not(Py_GIL_DISABLED)))]
119
#[inline(always)]
12-
pub(crate) fn get_unicode_key(key_str: &str) -> PyStr {
10+
pub(crate) fn get_unicode_key(key_str: &str) -> PyStrRef {
1311
if key_str.len() > 64 {
1412
cold_path!();
15-
PyStr::from_str_with_hash(key_str)
13+
PyStrRef::from_str_with_hash(key_str)
1614
} else {
1715
assume!(key_str.len() <= 64);
1816
let hash = xxhash_rust::xxh3::xxh3_64(key_str.as_bytes());
1917
unsafe {
20-
let entry = KEY_MAP
18+
let entry = crate::deserialize::cache::KEY_MAP
2119
.get_mut()
2220
.unwrap_or_else(|| unreachable_unchecked!())
2321
.entry(&hash)
2422
.or_insert_with(
2523
|| hash,
26-
|| CachedKey::new(PyStr::from_str_with_hash(key_str)),
24+
|| {
25+
crate::deserialize::cache::CachedKey::new(PyStrRef::from_str_with_hash(
26+
key_str,
27+
))
28+
},
2729
);
2830
entry.get()
2931
}
3032
}
3133
}
3234

33-
#[cfg(Py_GIL_DISABLED)]
35+
#[cfg(all(CPython, Py_GIL_DISABLED))]
3436
#[inline(always)]
35-
pub(crate) fn get_unicode_key(key_str: &str) -> PyStr {
36-
PyStr::from_str_with_hash(key_str)
37+
pub(crate) fn get_unicode_key(key_str: &str) -> PyStrRef {
38+
PyStrRef::from_str_with_hash(key_str)
39+
}
40+
41+
#[cfg(not(CPython))]
42+
#[inline(always)]
43+
pub(crate) fn get_unicode_key(key_str: &str) -> PyStrRef {
44+
PyStrRef::from_str(key_str)
3745
}
3846

3947
#[allow(dead_code)]

src/deserialize/utf8.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// SPDX-License-Identifier: (Apache-2.0 OR MIT)
2-
// Copyright ijl (2021-2025), Aarni Koskela (2021)
2+
// Copyright ijl (2021-2026), Aarni Koskela (2021)
33

44
use crate::deserialize::DeserializeError;
5+
use crate::ffi::PyStrRef;
56
use crate::ffi::{PyBytes_AS_STRING, PyBytes_GET_SIZE, PyMemoryView_GET_BUFFER};
6-
use crate::str::PyStr;
77
use crate::typeref::{BYTEARRAY_TYPE, BYTES_TYPE, MEMORYVIEW_TYPE, STR_TYPE};
88
use crate::util::INVALID_STR;
99
use crate::util::isize_to_usize;
@@ -50,8 +50,8 @@ pub(crate) fn read_input_to_buf(
5050
return Err(DeserializeError::invalid(Cow::Borrowed(INVALID_STR)));
5151
}
5252
} else if is_type!(obj_type_ptr, STR_TYPE) {
53-
let pystr = unsafe { PyStr::from_ptr_unchecked(ptr) };
54-
let uni = pystr.to_str();
53+
let pystr = unsafe { PyStrRef::from_ptr_unchecked(ptr) };
54+
let uni = pystr.as_str();
5555
if uni.is_none() {
5656
return Err(DeserializeError::invalid(Cow::Borrowed(INVALID_STR)));
5757
}

src/ffi/mod.rs

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,21 @@ mod bytes;
88
pub(crate) mod compat;
99
mod fragment;
1010
mod long;
11+
mod pystrref;
1112

12-
pub(crate) use buffer::*;
13-
pub(crate) use bytes::{PyBytes_AS_STRING, PyBytes_GET_SIZE, PyBytesObject};
1413
pub(crate) use compat::*;
1514

16-
pub(crate) use fragment::{Fragment, orjson_fragmenttype_new};
1715
pub(crate) use long::pylong_is_unsigned;
1816
#[cfg(feature = "inline_int")]
1917
pub(crate) use long::{pylong_fits_in_i32, pylong_get_inline_value, pylong_is_zero};
2018

19+
pub(crate) use {
20+
buffer::PyMemoryView_GET_BUFFER,
21+
bytes::{PyBytes_AS_STRING, PyBytes_GET_SIZE, PyBytesObject},
22+
fragment::{Fragment, orjson_fragmenttype_new},
23+
pystrref::{PyStrRef, PyStrSubclassRef, set_str_create_fn},
24+
};
25+
2126
#[allow(unused_imports)]
2227
pub(crate) use pyo3_ffi::{
2328
_PyBytes_Resize, METH_FASTCALL, METH_KEYWORDS, METH_O, Py_DECREF, Py_False, Py_INCREF, Py_None,
@@ -53,7 +58,7 @@ pub(crate) use pyo3_ffi::PyErr_Restore;
5358
#[cfg(CPython)]
5459
pub(crate) use pyo3_ffi::{PyObject_CallMethodNoArgs, PyObject_CallMethodOneArg};
5560

56-
#[cfg(all(CPython, not(target_endian = "little")))]
61+
#[cfg(not(feature = "inline_str"))]
5762
pub(crate) use pyo3_ffi::{PyUnicode_DATA, PyUnicode_KIND};
5863

5964
#[cfg(Py_3_12)]
Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// SPDX-License-Identifier: MPL-2.0
2-
// Copyright ijl (2024-2025)
2+
// Copyright ijl (2024-2026)
33

4-
use crate::str::pyunicode_new::*;
4+
use super::pyunicode_new::*;
55

66
use core::arch::x86_64::{
77
_mm512_and_si512, _mm512_cmpgt_epu8_mask, _mm512_cmpneq_epi8_mask, _mm512_loadu_epi8,

src/ffi/pystrref/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MPL-2.0
2+
// Copyright ijl (2026)
3+
4+
#[cfg(feature = "avx512")]
5+
#[cfg(CPython)]
6+
mod avx512;
7+
mod object;
8+
#[cfg(CPython)]
9+
mod pyunicode_new;
10+
#[cfg(CPython)]
11+
mod scalar;
12+
13+
pub(crate) use object::{PyStrRef, PyStrSubclassRef, set_str_create_fn};

0 commit comments

Comments
 (0)