Skip to content

Commit 4ee8e0d

Browse files
Make compatible with abi3
1 parent eb46ca2 commit 4ee8e0d

File tree

3 files changed

+49
-21
lines changed

3 files changed

+49
-21
lines changed

pyo3-ffi/src/compat/py_3_14.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ compat_function!(
2828
compat_function!(
2929
originally_defined_for(all(Py_3_14, not(Py_LIMITED_API)));
3030

31+
#[cfg(not(Py_LIMITED_API))]
3132
pub unsafe fn PyUnicodeWriter_Create(length: crate::Py_ssize_t) -> *mut crate::PyUnicodeWriter {
3233
if length < 0 {
3334
crate::PyErr_SetString(
@@ -52,6 +53,7 @@ compat_function!(
5253
compat_function!(
5354
originally_defined_for(all(Py_3_14, not(Py_LIMITED_API)));
5455

56+
#[cfg(not(Py_LIMITED_API))]
5557
pub unsafe fn PyUnicodeWriter_Finish(writer: *mut crate::PyUnicodeWriter) -> *mut crate::PyObject {
5658
let str = crate::_PyUnicodeWriter_Finish(writer.cast());
5759
crate::PyMem_Free(writer.cast());
@@ -62,6 +64,7 @@ compat_function!(
6264
compat_function!(
6365
originally_defined_for(all(Py_3_14, not(Py_LIMITED_API)));
6466

67+
#[cfg(not(Py_LIMITED_API))]
6568
pub unsafe fn PyUnicodeWriter_Discard(writer: *mut crate::PyUnicodeWriter) -> () {
6669
crate::_PyUnicodeWriter_Dealloc(writer.cast());
6770
crate::PyMem_Free(writer.cast())
@@ -71,6 +74,7 @@ compat_function!(
7174
compat_function!(
7275
originally_defined_for(all(Py_3_14, not(Py_LIMITED_API)));
7376

77+
#[cfg(not(Py_LIMITED_API))]
7478
pub unsafe fn PyUnicodeWriter_WriteChar(writer: *mut crate::PyUnicodeWriter, ch: crate::Py_UCS4) -> std::os::raw::c_int {
7579
if ch > 0x10ffff {
7680
crate::PyErr_SetString(
@@ -87,6 +91,7 @@ compat_function!(
8791
compat_function!(
8892
originally_defined_for(all(Py_3_14, not(Py_LIMITED_API)));
8993

94+
#[cfg(not(Py_LIMITED_API))]
9095
pub unsafe fn PyUnicodeWriter_WriteUTF8(writer: *mut crate::PyUnicodeWriter,str: *const std::os::raw::c_char, size: crate::Py_ssize_t) -> std::os::raw::c_int {
9196
let size = if size < 0 {
9297
libc::strlen(str) as isize

src/fmt.rs

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,36 @@
22
//! constructing Python strings using Rust's `fmt::Write` trait.
33
//! It allows for incremental string construction, without the need for repeated allocations, and
44
//! is particularly useful for building strings in a performance-sensitive context.
5-
use crate::ffi::compat::{
6-
PyUnicodeWriter_Create, PyUnicodeWriter_Discard, PyUnicodeWriter_Finish,
7-
PyUnicodeWriter_WriteChar, PyUnicodeWriter_WriteUTF8,
5+
#[cfg(not(Py_LIMITED_API))]
6+
use {
7+
crate::ffi::compat::{
8+
PyUnicodeWriter_Create, PyUnicodeWriter_Discard, PyUnicodeWriter_Finish,
9+
PyUnicodeWriter_WriteChar, PyUnicodeWriter_WriteUTF8,
10+
},
11+
crate::ffi_ptr_ext::FfiPtrExt,
12+
crate::impl_::callback::WrappingCastTo,
13+
crate::types::{PyAnyMethods, PyString},
14+
crate::{ffi, Bound, PyErr, PyResult, Python},
15+
std::ptr::NonNull,
16+
std::{fmt, mem},
817
};
9-
use crate::ffi_ptr_ext::FfiPtrExt;
10-
use crate::impl_::callback::WrappingCastTo;
11-
use crate::types::{PyAnyMethods, PyString};
12-
use crate::{ffi, Bound, PyErr, PyResult, Python};
13-
use std::ptr::NonNull;
14-
use std::{fmt, mem};
1518

19+
/// This is like the `format!` macro, but it returns a `PyString` instead of a `String`.
20+
#[macro_export]
21+
macro_rules! py_format {
22+
($py: expr, $($arg:tt)*) => {
23+
$crate::types::PyString::from_fmt($py, format_args!($($arg)*))
24+
}
25+
}
26+
27+
#[cfg(not(Py_LIMITED_API))]
1628
/// The `PyUnicodeWriter` is a utility for efficiently constructing Python strings
1729
pub struct PyUnicodeWriter {
1830
writer: NonNull<ffi::PyUnicodeWriter>,
1931
last_error: Option<PyErr>,
2032
}
2133

34+
#[cfg(not(Py_LIMITED_API))]
2235
impl PyUnicodeWriter {
2336
/// Creates a new `PyUnicodeWriter`.
2437
pub fn new(py: Python<'_>) -> PyResult<Self> {
@@ -63,6 +76,7 @@ impl PyUnicodeWriter {
6376
}
6477
}
6578

79+
#[cfg(not(Py_LIMITED_API))]
6680
impl fmt::Write for PyUnicodeWriter {
6781
fn write_str(&mut self, s: &str) -> fmt::Result {
6882
let result = unsafe {
@@ -87,6 +101,7 @@ impl fmt::Write for PyUnicodeWriter {
87101
}
88102
}
89103

104+
#[cfg(not(Py_LIMITED_API))]
90105
impl Drop for PyUnicodeWriter {
91106
fn drop(&mut self) {
92107
unsafe {
@@ -97,13 +112,15 @@ impl Drop for PyUnicodeWriter {
97112

98113
#[cfg(test)]
99114
mod tests {
115+
#[cfg(not(Py_LIMITED_API))]
100116
use super::*;
101117
use crate::types::PyStringMethods;
102118
use crate::{IntoPyObject, Python};
103-
use std::fmt::Write;
104119

105120
#[test]
121+
#[cfg(not(Py_LIMITED_API))]
106122
fn unicode_writer_test() {
123+
use std::fmt::Write;
107124
Python::with_gil(|py| {
108125
let mut writer = PyUnicodeWriter::new(py).unwrap();
109126
write!(writer, "Hello {}!", "world").unwrap();
@@ -116,19 +133,15 @@ mod tests {
116133
#[test]
117134
fn test_pystring_from_fmt() {
118135
Python::with_gil(|py| {
119-
PyString::from_fmt(py, format_args!("Hello {}!", "world")).unwrap();
136+
py_format!(py, "Hello {}!", "world").unwrap();
120137
});
121138
}
122139

123140
#[test]
124141
fn test_complex_format() {
125142
Python::with_gil(|py| {
126143
let complex_value = (42, "foo", 3.14).into_pyobject(py).unwrap();
127-
let py_string = PyString::from_fmt(
128-
py,
129-
format_args!("This is some complex value: {complex_value}"),
130-
)
131-
.unwrap();
144+
let py_string = py_format!(py, "This is some complex value: {complex_value}").unwrap();
132145
let actual = py_string.to_cow().unwrap();
133146
let expected = "This is some complex value: (42, 'foo', 3.14)";
134147
assert_eq!(actual, expected);

src/types/string.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#[cfg(not(Py_LIMITED_API))]
22
use crate::exceptions::PyUnicodeDecodeError;
33
use crate::ffi_ptr_ext::FfiPtrExt;
4+
#[cfg(not(Py_LIMITED_API))]
45
use crate::fmt::PyUnicodeWriter;
56
use crate::instance::Borrowed;
67
use crate::py_result_ext::PyResultExt;
@@ -10,6 +11,7 @@ use crate::types::PyBytes;
1011
use crate::{ffi, Bound, Py, PyAny, PyResult, Python};
1112
use std::borrow::Cow;
1213
use std::ffi::CString;
14+
#[cfg(not(Py_LIMITED_API))]
1315
use std::fmt::Write as _;
1416
use std::{fmt, str};
1517

@@ -223,11 +225,19 @@ impl PyString {
223225
return Ok(PyString::new(py, static_string));
224226
};
225227

226-
let mut writer = PyUnicodeWriter::new(py)?;
227-
writer
228-
.write_fmt(args)
229-
.map_err(|_| writer.take_error().expect("expected error"))?;
230-
writer.into_py_string(py)
228+
#[cfg(not(Py_LIMITED_API))]
229+
{
230+
let mut writer = PyUnicodeWriter::new(py)?;
231+
writer
232+
.write_fmt(args)
233+
.map_err(|_| writer.take_error().expect("expected error"))?;
234+
writer.into_py_string(py)
235+
}
236+
237+
#[cfg(Py_LIMITED_API)]
238+
{
239+
Ok(PyString::new(py, &format!("{args}")))
240+
}
231241
}
232242
}
233243

0 commit comments

Comments
 (0)