Skip to content

Commit 1593104

Browse files
Add BytesWriter
1 parent 99aa9bd commit 1593104

File tree

7 files changed

+403
-0
lines changed

7 files changed

+403
-0
lines changed

newsfragments/5517.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add `BytesWriter`

pyo3-ffi/src/bytesobject.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,17 @@ extern "C" {
5656
) -> c_int;
5757
}
5858

59+
#[cfg(Py_3_15)]
60+
opaque_struct!(pub PyBytesWriter);
61+
62+
#[repr(C)]
63+
#[cfg(not(Py_3_15))]
64+
pub struct PyBytesWriter {
65+
pub(crate) small_buffer: [c_char; 256],
66+
pub(crate) obj: *mut PyObject,
67+
pub(crate) size: Py_ssize_t,
68+
}
69+
5970
// skipped F_LJUST
6071
// skipped F_SIGN
6172
// skipped F_BLANK

pyo3-ffi/src/compat/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ macro_rules! compat_function {
5353
mod py_3_10;
5454
mod py_3_13;
5555
mod py_3_14;
56+
mod py_3_15;
5657
mod py_3_9;
5758

5859
pub use self::py_3_10::*;
5960
pub use self::py_3_13::*;
6061
pub use self::py_3_14::*;
62+
pub use self::py_3_15::*;
6163
pub use self::py_3_9::*;

pyo3-ffi/src/compat/py_3_15.rs

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
compat_function!(
2+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
3+
4+
#[inline]
5+
pub unsafe fn PyBytesWriter_Create(
6+
size: crate::Py_ssize_t,
7+
) -> *mut crate::PyBytesWriter {
8+
9+
if size < 0 {
10+
crate::PyErr_SetString(crate::PyExc_ValueError, c_str!("size must be >= 0").as_ptr() as *const _);
11+
return std::ptr::null_mut();
12+
}
13+
14+
let writer: *mut crate::PyBytesWriter = crate::PyMem_Malloc(size_of::<crate::PyBytesWriter>()).cast();
15+
if writer.is_null() {
16+
crate::PyErr_NoMemory();
17+
return std::ptr::null_mut();
18+
}
19+
20+
(*writer).obj = std::ptr::null_mut();
21+
(*writer).size = 0;
22+
23+
if size >=1 {
24+
if _PyBytesWriter_Resize_impl(writer, size, 0) < 0 {
25+
PyBytesWriter_Discard(writer);
26+
return std::ptr::null_mut();
27+
}
28+
29+
(*writer).size = size;
30+
}
31+
32+
writer
33+
}
34+
);
35+
36+
compat_function!(
37+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
38+
39+
#[inline]
40+
pub unsafe fn PyBytesWriter_Discard(writer: *mut crate::PyBytesWriter) -> () {
41+
if writer.is_null() {
42+
return;
43+
}
44+
45+
crate::Py_XDECREF((*writer).obj);
46+
crate::PyMem_Free(writer.cast());
47+
}
48+
);
49+
50+
compat_function!(
51+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
52+
53+
#[inline]
54+
pub unsafe fn PyBytesWriter_Finish(writer: *mut crate::PyBytesWriter) -> *mut crate::PyObject {
55+
PyBytesWriter_FinishWithSize(writer, (*writer).size)
56+
}
57+
);
58+
59+
compat_function!(
60+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
61+
62+
#[inline]
63+
pub unsafe fn PyBytesWriter_FinishWithSize(writer: *mut crate::PyBytesWriter, size: crate::Py_ssize_t) -> *mut crate::PyObject {
64+
let result = if size == 0 {
65+
crate:: PyBytes_FromStringAndSize(c_str!("").as_ptr(), 0)
66+
} else if (*writer).obj.is_null() {
67+
crate::PyBytes_FromStringAndSize((*writer).small_buffer.as_ptr(), size)
68+
} else {
69+
if size != crate::PyBytes_Size((*writer).obj) && crate::_PyBytes_Resize(&mut (*writer).obj, size) < 0{
70+
71+
PyBytesWriter_Discard(writer);
72+
return std::ptr::null_mut();
73+
74+
}
75+
std::mem::take(&mut (*writer).obj)
76+
};
77+
78+
PyBytesWriter_Discard(writer);
79+
result
80+
}
81+
);
82+
83+
compat_function!(
84+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
85+
86+
#[inline]
87+
pub unsafe fn _PyBytesWriter_GetAllocated(writer: *mut crate::PyBytesWriter) -> crate::Py_ssize_t {
88+
if (*writer).obj.is_null() {
89+
size_of_val(&(*writer).small_buffer) as _
90+
} else {
91+
crate::PyBytes_Size((*writer).obj)
92+
}
93+
}
94+
);
95+
96+
compat_function!(
97+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
98+
99+
#[inline]
100+
pub unsafe fn PyBytesWriter_GetData(writer: *mut crate::PyBytesWriter) -> *mut std::ffi::c_void {
101+
if (*writer).obj.is_null() {
102+
(*writer).small_buffer.as_ptr() as *mut _
103+
} else {
104+
#[cfg(Py_LIMITED_API)]
105+
{
106+
crate::PyBytes_AsString((*writer).obj) as *mut _
107+
}
108+
109+
#[cfg(not(Py_LIMITED_API))]
110+
{
111+
crate::PyBytes_AS_STRING((*writer).obj) as *mut _
112+
}
113+
}
114+
}
115+
);
116+
117+
compat_function!(
118+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
119+
120+
#[inline]
121+
pub unsafe fn PyBytesWriter_GetSize(writer: *mut crate::PyBytesWriter) -> crate::Py_ssize_t {
122+
(*writer).size
123+
}
124+
);
125+
126+
compat_function!(
127+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
128+
129+
#[inline]
130+
pub unsafe fn PyBytesWriter_WriteBytes(writer: *mut crate::PyBytesWriter, bytes: *const std::ffi::c_void, size: crate::Py_ssize_t) -> std::ffi::c_int {
131+
let size = if size < 0 {
132+
let len = libc::strlen(bytes as _);
133+
if len > crate::PY_SSIZE_T_MAX as libc::size_t {
134+
crate::PyErr_NoMemory();
135+
return -1;
136+
}
137+
len as crate::Py_ssize_t
138+
} else {
139+
size
140+
};
141+
142+
let pos = (*writer).size;
143+
if PyBytesWriter_Grow(writer, size) < 0 {
144+
return -1;
145+
}
146+
147+
let buf = PyBytesWriter_GetData(writer);
148+
std::ptr::copy_nonoverlapping(bytes, buf.add(pos as usize), size as usize);
149+
0
150+
}
151+
);
152+
153+
compat_function!(
154+
originally_defined_for(all(Py_3_15, not(Py_LIMITED_API)));
155+
156+
#[inline]
157+
pub unsafe fn PyBytesWriter_Grow(writer: *mut crate::PyBytesWriter, size: crate::Py_ssize_t) -> std::ffi::c_int {
158+
if size < 0 && (*writer).size + size < 0 {
159+
crate::PyErr_SetString(crate::PyExc_ValueError, c_str!("invalid size").as_ptr());
160+
return -1;
161+
}
162+
163+
if size > crate::PY_SSIZE_T_MAX - (*writer).size {
164+
crate::PyErr_NoMemory();
165+
return -1;
166+
}
167+
let new_size = (*writer).size + size;
168+
169+
if _PyBytesWriter_Resize_impl(writer, new_size, 1) < 0 {
170+
return -1;
171+
}
172+
173+
(*writer).size = new_size;
174+
0
175+
}
176+
);
177+
178+
#[inline]
179+
unsafe fn _PyBytesWriter_Resize_impl(
180+
writer: *mut crate::PyBytesWriter,
181+
mut size: crate::Py_ssize_t,
182+
resize: std::ffi::c_int,
183+
) -> std::ffi::c_int {
184+
let overallocate = resize;
185+
assert!(size >= 0);
186+
187+
if size <= _PyBytesWriter_GetAllocated(writer) {
188+
return 0;
189+
}
190+
191+
if overallocate > 0 {
192+
#[cfg(windows)]
193+
if size <= (crate::PY_SSIZE_T_MAX - size / 2) {
194+
size += size / 2;
195+
}
196+
197+
#[cfg(not(windows))]
198+
if size <= (crate::PY_SSIZE_T_MAX - size / 4) {
199+
size += size / 4;
200+
}
201+
}
202+
203+
if !(*writer).obj.is_null() {
204+
if crate::_PyBytes_Resize(&mut (*writer).obj, size) > 0 {
205+
return -1;
206+
}
207+
assert!(!(*writer).obj.is_null())
208+
} else {
209+
(*writer).obj = crate::PyBytes_FromStringAndSize(std::ptr::null_mut(), size);
210+
if (*writer).obj.is_null() {
211+
return -1;
212+
}
213+
214+
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 _;
222+
223+
std::ptr::copy_nonoverlapping(
224+
(*writer).small_buffer.as_ptr(),
225+
dest,
226+
size_of_val(&(*writer).small_buffer),
227+
);
228+
}
229+
}
230+
231+
0
232+
}

0 commit comments

Comments
 (0)