Skip to content

Commit 0a38fa8

Browse files
Support abi3 using Vec
fix msrv
1 parent a8e2c89 commit 0a38fa8

File tree

2 files changed

+121
-44
lines changed

2 files changed

+121
-44
lines changed

pyo3-ffi/src/compat/py_3_15.rs

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
#[cfg(not(Py_LIMITED_API))]
12
compat_function!(
23
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
34

@@ -11,7 +12,7 @@ compat_function!(
1112
return std::ptr::null_mut();
1213
}
1314

14-
let writer: *mut crate::PyBytesWriter = crate::PyMem_Malloc(size_of::<crate::PyBytesWriter>()).cast();
15+
let writer: *mut crate::PyBytesWriter = crate::PyMem_Malloc(std::mem::size_of::<crate::PyBytesWriter>()).cast();
1516
if writer.is_null() {
1617
crate::PyErr_NoMemory();
1718
return std::ptr::null_mut();
@@ -33,6 +34,7 @@ compat_function!(
3334
}
3435
);
3536

37+
#[cfg(not(Py_LIMITED_API))]
3638
compat_function!(
3739
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
3840

@@ -47,6 +49,7 @@ compat_function!(
4749
}
4850
);
4951

52+
#[cfg(not(Py_LIMITED_API))]
5053
compat_function!(
5154
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
5255

@@ -56,43 +59,44 @@ compat_function!(
5659
}
5760
);
5861

62+
#[cfg(not(Py_LIMITED_API))]
5963
compat_function!(
6064
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
6165

6266
#[inline]
6367
pub unsafe fn PyBytesWriter_FinishWithSize(writer: *mut crate::PyBytesWriter, size: crate::Py_ssize_t) -> *mut crate::PyObject {
6468
let result = if size == 0 {
65-
crate:: PyBytes_FromStringAndSize(c_str!("").as_ptr(), 0)
69+
crate::PyBytes_FromStringAndSize(c_str!("").as_ptr(), 0)
6670
} else if (*writer).obj.is_null() {
6771
crate::PyBytes_FromStringAndSize((*writer).small_buffer.as_ptr(), size)
6872
} else {
6973
if size != crate::PyBytes_Size((*writer).obj) && crate::_PyBytes_Resize(&mut (*writer).obj, size) < 0{
70-
7174
PyBytesWriter_Discard(writer);
7275
return std::ptr::null_mut();
73-
7476
}
75-
std::mem::take(&mut (*writer).obj)
77+
std::mem::replace(&mut (*writer).obj, std::ptr::null_mut())
7678
};
7779

7880
PyBytesWriter_Discard(writer);
7981
result
8082
}
8183
);
8284

85+
#[cfg(not(Py_LIMITED_API))]
8386
compat_function!(
8487
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
8588

8689
#[inline]
8790
pub unsafe fn _PyBytesWriter_GetAllocated(writer: *mut crate::PyBytesWriter) -> crate::Py_ssize_t {
8891
if (*writer).obj.is_null() {
89-
size_of_val(&(*writer).small_buffer) as _
92+
std::mem::size_of_val(&(*writer).small_buffer) as _
9093
} else {
9194
crate::PyBytes_Size((*writer).obj)
9295
}
9396
}
9497
);
9598

99+
#[cfg(not(Py_LIMITED_API))]
96100
compat_function!(
97101
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
98102

@@ -101,19 +105,12 @@ compat_function!(
101105
if (*writer).obj.is_null() {
102106
(*writer).small_buffer.as_ptr() as *mut _
103107
} else {
104-
#[cfg(Py_LIMITED_API)]
105-
{
106-
crate::PyBytes_AsString((*writer).obj) as *mut _
107-
}
108-
109-
#[cfg(not(Py_LIMITED_API))]
110-
{
111108
crate::PyBytes_AS_STRING((*writer).obj) as *mut _
112-
}
113109
}
114110
}
115111
);
116112

113+
#[cfg(not(Py_LIMITED_API))]
117114
compat_function!(
118115
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
119116

@@ -123,6 +120,7 @@ compat_function!(
123120
}
124121
);
125122

123+
#[cfg(not(Py_LIMITED_API))]
126124
compat_function!(
127125
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
128126

@@ -150,6 +148,7 @@ compat_function!(
150148
}
151149
);
152150

151+
#[cfg(not(Py_LIMITED_API))]
153152
compat_function!(
154153
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
155154

@@ -176,6 +175,7 @@ compat_function!(
176175
);
177176

178177
#[inline]
178+
#[cfg(not(Py_LIMITED_API))]
179179
unsafe fn _PyBytesWriter_Resize_impl(
180180
writer: *mut crate::PyBytesWriter,
181181
mut size: crate::Py_ssize_t,
@@ -212,18 +212,12 @@ unsafe fn _PyBytesWriter_Resize_impl(
212212
}
213213

214214
if resize > 0 {
215-
assert!((size as usize) > size_of_val(&(*writer).small_buffer));
216-
217-
#[cfg(Py_LIMITED_API)]
218-
let dest = crate::PyBytes_AsString((*writer).obj) as *mut _;
219-
220-
#[cfg(not(Py_LIMITED_API))]
221-
let dest = crate::PyBytes_AS_STRING((*writer).obj) as *mut _;
215+
assert!((size as usize) > std::mem::size_of_val(&(*writer).small_buffer));
222216

223217
std::ptr::copy_nonoverlapping(
224218
(*writer).small_buffer.as_ptr(),
225-
dest,
226-
size_of_val(&(*writer).small_buffer),
219+
crate::PyBytes_AS_STRING((*writer).obj) as *mut _,
220+
std::mem::size_of_val(&(*writer).small_buffer),
227221
);
228222
}
229223
}

src/byteswriter.rs

Lines changed: 104 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
1-
use crate::ffi_ptr_ext::FfiPtrExt;
2-
use crate::py_result_ext::PyResultExt;
31
use crate::types::PyBytes;
4-
use crate::{ffi, Bound, PyErr, PyResult, Python};
5-
use pyo3_ffi::compat::{
6-
PyBytesWriter_Create, PyBytesWriter_Discard, PyBytesWriter_Finish, PyBytesWriter_GetData,
7-
PyBytesWriter_GetSize, PyBytesWriter_Grow, PyBytesWriter_WriteBytes,
8-
_PyBytesWriter_GetAllocated,
2+
#[cfg(not(Py_LIMITED_API))]
3+
use crate::{
4+
ffi::{
5+
self,
6+
compat::{
7+
PyBytesWriter_Create, PyBytesWriter_Discard, PyBytesWriter_Finish,
8+
PyBytesWriter_GetData, PyBytesWriter_GetSize, PyBytesWriter_Grow,
9+
PyBytesWriter_WriteBytes, _PyBytesWriter_GetAllocated,
10+
},
11+
},
12+
ffi_ptr_ext::FfiPtrExt,
13+
py_result_ext::PyResultExt,
914
};
15+
use crate::{Bound, IntoPyObject, PyErr, PyResult, Python};
1016
use std::io::IoSlice;
11-
use std::ptr;
12-
use std::ptr::NonNull;
17+
#[cfg(not(Py_LIMITED_API))]
18+
use std::ptr::{self, NonNull};
1319

1420
pub struct PyBytesWriter<'py> {
1521
python: Python<'py>,
22+
#[cfg(not(Py_LIMITED_API))]
1623
writer: NonNull<ffi::PyBytesWriter>,
24+
#[cfg(Py_LIMITED_API)]
25+
buffer: Vec<u8>,
1726
}
1827

1928
impl<'py> PyBytesWriter<'py> {
@@ -24,51 +33,97 @@ impl<'py> PyBytesWriter<'py> {
2433

2534
#[inline]
2635
pub fn with_capacity(py: Python<'py>, capacity: usize) -> PyResult<Self> {
27-
match NonNull::new(unsafe { PyBytesWriter_Create(capacity as _) }) {
28-
Some(ptr) => Ok(PyBytesWriter {
36+
#[cfg(not(Py_LIMITED_API))]
37+
{
38+
NonNull::new(unsafe { PyBytesWriter_Create(capacity as _) })
39+
.map(|writer| PyBytesWriter { python: py, writer })
40+
.ok_or_else(|| PyErr::fetch(py))
41+
}
42+
43+
#[cfg(Py_LIMITED_API)]
44+
{
45+
Ok(PyBytesWriter {
2946
python: py,
30-
writer: ptr,
31-
}),
32-
None => Err(PyErr::fetch(py)),
47+
buffer: Vec::with_capacity(capacity),
48+
})
3349
}
3450
}
3551

3652
#[inline]
3753
pub fn capacity(&self) -> usize {
38-
unsafe { _PyBytesWriter_GetAllocated(self.writer.as_ptr()) as _ }
54+
#[cfg(not(Py_LIMITED_API))]
55+
unsafe {
56+
_PyBytesWriter_GetAllocated(self.writer.as_ptr()) as _
57+
}
58+
59+
#[cfg(Py_LIMITED_API)]
60+
{
61+
self.buffer.capacity()
62+
}
3963
}
4064

4165
#[inline]
4266
pub fn len(&self) -> usize {
43-
unsafe { PyBytesWriter_GetSize(self.writer.as_ptr()) as _ }
67+
#[cfg(not(Py_LIMITED_API))]
68+
unsafe {
69+
PyBytesWriter_GetSize(self.writer.as_ptr()) as _
70+
}
71+
72+
#[cfg(Py_LIMITED_API)]
73+
{
74+
self.buffer.len()
75+
}
4476
}
4577

4678
#[inline]
79+
#[cfg(not(Py_LIMITED_API))]
4780
fn as_mut_ptr(&mut self) -> *mut u8 {
4881
unsafe { PyBytesWriter_GetData(self.writer.as_ptr()) as _ }
4982
}
5083
}
5184

52-
impl<'py> TryInto<Bound<'py, PyBytes>> for PyBytesWriter<'py> {
85+
#[cfg(not(Py_LIMITED_API))]
86+
impl<'py> TryFrom<PyBytesWriter<'py>> for Bound<'py, PyBytes> {
5387
type Error = PyErr;
5488

5589
#[inline]
56-
fn try_into(self) -> PyResult<Bound<'py, PyBytes>> {
90+
fn try_from(value: PyBytesWriter<'py>) -> Result<Self, Self::Error> {
5791
unsafe {
58-
PyBytesWriter_Finish(self.writer.as_ptr())
59-
.assume_owned_or_err(self.python)
92+
PyBytesWriter_Finish(value.writer.as_ptr())
93+
.assume_owned_or_err(value.python)
6094
.cast_into_unchecked()
6195
}
6296
}
6397
}
6498

99+
#[cfg(Py_LIMITED_API)]
100+
impl<'py> From<PyBytesWriter<'py>> for Bound<'py, PyBytes> {
101+
#[inline]
102+
fn from(writer: PyBytesWriter<'py>) -> Self {
103+
PyBytes::new(writer.python, &writer.buffer)
104+
}
105+
}
106+
107+
impl<'py> IntoPyObject<'py> for PyBytesWriter<'py> {
108+
type Target = PyBytes;
109+
type Output = Bound<'py, PyBytes>;
110+
type Error = PyErr;
111+
112+
#[inline]
113+
fn into_pyobject(self, _py: Python<'py>) -> Result<Self::Output, Self::Error> {
114+
self.try_into().map_err(Into::into)
115+
}
116+
}
117+
118+
#[cfg(not(Py_LIMITED_API))]
65119
impl<'py> Drop for PyBytesWriter<'py> {
66120
#[inline]
67121
fn drop(&mut self) {
68122
unsafe { PyBytesWriter_Discard(self.writer.as_ptr()) }
69123
}
70124
}
71125

126+
#[cfg(not(Py_LIMITED_API))]
72127
impl std::io::Write for PyBytesWriter<'_> {
73128
#[inline]
74129
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
@@ -114,6 +169,34 @@ impl std::io::Write for PyBytesWriter<'_> {
114169
}
115170
}
116171

172+
#[cfg(Py_LIMITED_API)]
173+
impl std::io::Write for PyBytesWriter<'_> {
174+
#[inline]
175+
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
176+
self.buffer.write(buf)
177+
}
178+
179+
#[inline]
180+
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> std::io::Result<usize> {
181+
self.buffer.write_vectored(bufs)
182+
}
183+
184+
#[inline]
185+
fn flush(&mut self) -> std::io::Result<()> {
186+
self.buffer.flush()
187+
}
188+
189+
#[inline]
190+
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
191+
self.buffer.write_all(buf)
192+
}
193+
194+
#[inline]
195+
fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> {
196+
self.buffer.write_fmt(args)
197+
}
198+
}
199+
117200
#[cfg(test)]
118201
mod tests {
119202
use super::*;
@@ -122,7 +205,7 @@ mod tests {
122205
#[test]
123206
fn test_io_write() {
124207
Python::attach(|py| {
125-
let buf: [u8; _] = [1, 2, 3, 4];
208+
let buf = [1, 2, 3, 4];
126209
let mut writer = PyBytesWriter::new(py).unwrap();
127210
writer.write(&buf).unwrap();
128211
let bytes: Bound<'_, PyBytes> = writer.try_into().unwrap();

0 commit comments

Comments
 (0)