Skip to content

Commit

Permalink
ci: add Python 3.12-dev jobs
Browse files Browse the repository at this point in the history
  • Loading branch information
davidhewitt committed Nov 22, 2022
1 parent 0842355 commit 349281d
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 18 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ jobs:
"3.9",
"3.10",
"3.11",
"3.12-dev",
"pypy-3.7",
"pypy-3.8",
"pypy-3.9"
Expand Down
46 changes: 44 additions & 2 deletions pyo3-ffi/src/cpython/unicodeobject.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#[cfg(not(PyPy))]
use crate::Py_hash_t;
use crate::{PyObject, Py_UCS1, Py_UCS2, Py_UCS4, Py_UNICODE, Py_ssize_t};
#[cfg(not(Py_3_12))]
use libc::wchar_t;
use std::os::raw::{c_char, c_int, c_uint, c_void};

Expand Down Expand Up @@ -48,6 +49,7 @@ pub struct PyASCIIObject {
/// unsigned int ready:1;
/// unsigned int :24;
pub state: u32,
#[cfg(not(Py_3_12))]
pub wstr: *mut wchar_t,
}

Expand All @@ -56,6 +58,7 @@ pub struct PyASCIIObject {
/// In addition, they are disabled on big-endian architectures to restrict this to most "common"
/// platforms, which are at least tested on CI and appear to be sound.
#[cfg(target_endian = "little")]
#[cfg(not(Py_3_12))]
impl PyASCIIObject {
#[inline]
pub unsafe fn interned(&self) -> c_uint {
Expand Down Expand Up @@ -83,11 +86,35 @@ impl PyASCIIObject {
}
}

#[cfg(Py_3_12)]
impl PyASCIIObject {
#[inline]
pub unsafe fn interned(&self) -> c_uint {
self.state & 1
}

#[inline]
pub unsafe fn kind(&self) -> c_uint {
(self.state >> 1) & 7
}

#[inline]
pub unsafe fn compact(&self) -> c_uint {
(self.state >> 4) & 1
}

#[inline]
pub unsafe fn ascii(&self) -> c_uint {
(self.state >> 5) & 1
}
}

#[repr(C)]
pub struct PyCompactUnicodeObject {
pub _base: PyASCIIObject,
pub utf8_length: Py_ssize_t,
pub utf8: *mut c_char,
#[cfg(not(Py_3_12))]
pub wstr_length: Py_ssize_t,
}

Expand Down Expand Up @@ -123,6 +150,7 @@ pub const SSTATE_INTERNED_IMMORTAL: c_uint = 2;
#[cfg(target_endian = "little")]
pub unsafe fn PyUnicode_IS_ASCII(op: *mut PyObject) -> c_uint {
debug_assert!(crate::PyUnicode_Check(op) != 0);
#[cfg(not(Py_3_12))]
debug_assert!(PyUnicode_IS_READY(op) != 0);

(*(op as *mut PyASCIIObject)).ascii()
Expand All @@ -141,7 +169,7 @@ pub unsafe fn PyUnicode_IS_COMPACT_ASCII(op: *mut PyObject) -> c_uint {
}

#[cfg(not(Py_3_12))]
#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))]
#[deprecated(note = "Removed in Python 3.12")]
pub const PyUnicode_WCHAR_KIND: c_uint = 0;

pub const PyUnicode_1BYTE_KIND: c_uint = 1;
Expand Down Expand Up @@ -170,6 +198,7 @@ pub unsafe fn PyUnicode_4BYTE_DATA(op: *mut PyObject) -> *mut Py_UCS4 {
#[cfg(target_endian = "little")]
pub unsafe fn PyUnicode_KIND(op: *mut PyObject) -> c_uint {
debug_assert!(crate::PyUnicode_Check(op) != 0);
#[cfg(not(Py_3_12))]
debug_assert!(PyUnicode_IS_READY(op) != 0);

(*(op as *mut PyASCIIObject)).kind()
Expand Down Expand Up @@ -213,19 +242,26 @@ pub unsafe fn PyUnicode_DATA(op: *mut PyObject) -> *mut c_void {
#[cfg(target_endian = "little")]
pub unsafe fn PyUnicode_GET_LENGTH(op: *mut PyObject) -> Py_ssize_t {
debug_assert!(crate::PyUnicode_Check(op) != 0);
#[cfg(not(Py_3_12))]
debug_assert!(PyUnicode_IS_READY(op) != 0);

(*(op as *mut PyASCIIObject)).length
}

#[inline]
#[cfg(not(Py_3_12))]
#[cfg(target_endian = "little")]
pub unsafe fn PyUnicode_IS_READY(op: *mut PyObject) -> c_uint {
(*(op as *mut PyASCIIObject)).ready()
}

#[inline]
#[cfg(Py_3_12)]
pub unsafe fn PyUnicode_IS_READY(_: *mut PyObject) -> c_uint {
1
}

#[cfg(not(Py_3_12))]
#[cfg_attr(Py_3_10, deprecated(note = "Python 3.10"))]
#[inline]
#[cfg(target_endian = "little")]
pub unsafe fn PyUnicode_READY(op: *mut PyObject) -> c_int {
Expand All @@ -238,6 +274,12 @@ pub unsafe fn PyUnicode_READY(op: *mut PyObject) -> c_int {
}
}

#[cfg(Py_3_12)]
#[inline]
pub unsafe fn PyUnicode_READY(_: *mut PyObject) -> c_int {
0
}

// skipped PyUnicode_MAX_CHAR_VALUE
// skipped _PyUnicode_get_wstr_length
// skipped PyUnicode_WSTR_LENGTH
Expand Down
2 changes: 2 additions & 0 deletions pyo3-ffi/src/unicodeobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ extern "C" {
pub fn PyUnicode_AsUCS4Copy(unicode: *mut PyObject) -> *mut Py_UCS4;
#[cfg_attr(PyPy, link_name = "PyPyUnicode_GetLength")]
pub fn PyUnicode_GetLength(unicode: *mut PyObject) -> Py_ssize_t;
#[cfg(not(Py_3_12))]
#[deprecated(note = "Removed in Python 3.12")]
#[cfg_attr(PyPy, link_name = "PyPyUnicode_GetSize")]
pub fn PyUnicode_GetSize(unicode: *mut PyObject) -> Py_ssize_t;
pub fn PyUnicode_ReadChar(unicode: *mut PyObject, index: Py_ssize_t) -> Py_UCS4;
Expand Down
67 changes: 51 additions & 16 deletions src/ffi/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{types::PyDict, AsPyPointer, IntoPy, Py, PyAny, Python};

#[cfg(target_endian = "little")]
use crate::types::PyString;
#[cfg(target_endian = "little")]
#[cfg(all(target_endian = "little", not(Py_3_12)))]
use libc::wchar_t;

#[cfg_attr(target_arch = "wasm32", ignore)] // DateTime import fails on wasm for mysterious reasons
Expand Down Expand Up @@ -119,6 +119,7 @@ fn ascii_object_bitfield() {
#[cfg(not(PyPy))]
hash: 0,
state: 0,
#[cfg(not(Py_3_12))]
wstr: std::ptr::null_mut() as *mut wchar_t,
};

Expand All @@ -127,26 +128,58 @@ fn ascii_object_bitfield() {
assert_eq!(o.kind(), 0);
assert_eq!(o.compact(), 0);
assert_eq!(o.ascii(), 0);
#[cfg(not(Py_3_12))]
assert_eq!(o.ready(), 0);

for i in 0..4 {
o.state = i;
assert_eq!(o.interned(), i);
#[cfg(not(Py_3_12))]
{
for i in 0..4 {
o.state = i;
assert_eq!(o.interned(), i);
}

for i in 0..8 {
o.state = i << 2;
assert_eq!(o.kind(), i);
}

o.state = 0;
assert_eq!(o.compact(), 0);
o.state = 1 << 5;
assert_eq!(o.compact(), 1);

o.state = 0;
assert_eq!(o.ascii(), 0);
o.state = 1 << 6;
assert_eq!(o.ascii(), 1);

o.state = 0;
assert_eq!(o.ready(), 0);
o.state = 1 << 7;
assert_eq!(o.ready(), 1);
}

for i in 0..8 {
o.state = i << 2;
assert_eq!(o.kind(), i);
#[cfg(Py_3_12)]
{
assert_eq!(o.interned(), 0);
o.state = 1;
assert_eq!(o.interned(), 1);

for i in 0..8 {
o.state = i << 1;
assert_eq!(o.kind(), i);
}

o.state = 0;
assert_eq!(o.compact(), 0);
o.state = 1 << 4;
assert_eq!(o.compact(), 1);

o.state = 0;
assert_eq!(o.ascii(), 0);
o.state = 1 << 5;
assert_eq!(o.ascii(), 1);
}

o.state = 1 << 5;
assert_eq!(o.compact(), 1);

o.state = 1 << 6;
assert_eq!(o.ascii(), 1);

o.state = 1 << 7;
assert_eq!(o.ready(), 1);
}
}

Expand All @@ -167,6 +200,7 @@ fn ascii() {
assert_eq!(ascii.kind(), PyUnicode_1BYTE_KIND);
assert_eq!(ascii.compact(), 1);
assert_eq!(ascii.ascii(), 1);
#[cfg(not(Py_3_12))]
assert_eq!(ascii.ready(), 1);

assert_eq!(PyUnicode_IS_ASCII(ptr), 1);
Expand Down Expand Up @@ -208,6 +242,7 @@ fn ucs4() {
assert_eq!(ascii.kind(), PyUnicode_4BYTE_KIND);
assert_eq!(ascii.compact(), 1);
assert_eq!(ascii.ascii(), 0);
#[cfg(not(Py_3_12))]
assert_eq!(ascii.ready(), 1);

assert_eq!(PyUnicode_IS_ASCII(ptr), 0);
Expand Down

0 comments on commit 349281d

Please sign in to comment.