Skip to content

Commit 03a9d60

Browse files
authored
Refactor Buffer Protocol (mostly namings) (RustPython#2849)
* Refactor Buffer protocol into RustPython convention
1 parent 0906728 commit 03a9d60

File tree

10 files changed

+137
-87
lines changed

10 files changed

+137
-87
lines changed

derive/src/pyclass.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -395,7 +395,8 @@ where
395395
Self::#ident as _
396396
}
397397
};
398-
if slot_name == "new" || slot_name == "buffer" {
398+
const NON_ATOMIC_SLOTS: &[&str] = &["new", "as_buffer"];
399+
if NON_ATOMIC_SLOTS.contains(&slot_name.as_str()) {
399400
quote! {
400401
slots.#slot_ident = Some(#into_func);
401402
}

vm/src/builtins/bytearray.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use super::bytes::{PyBytes, PyBytesRef};
33
use super::dict::PyDictRef;
44
use super::int::PyIntRef;
5-
use super::memory::{Buffer, BufferOptions, ResizeGuard};
5+
use super::memory::{BufferOptions, PyBuffer, ResizeGuard};
66
use super::pystr::PyStrRef;
77
use super::pytype::PyTypeRef;
88
use super::tuple::PyTupleRef;
@@ -668,7 +668,7 @@ impl Comparable for PyByteArray {
668668
}
669669

670670
impl BufferProtocol for PyByteArray {
671-
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
671+
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn PyBuffer>> {
672672
zelf.exports.fetch_add(1);
673673
let buf = ByteArrayBuffer {
674674
bytearray: zelf.clone(),
@@ -688,7 +688,7 @@ struct ByteArrayBuffer {
688688
options: BufferOptions,
689689
}
690690

691-
impl Buffer for ByteArrayBuffer {
691+
impl PyBuffer for ByteArrayBuffer {
692692
fn obj_bytes(&self) -> BorrowedValue<[u8]> {
693693
self.bytearray.borrow_buf().into()
694694
}

vm/src/builtins/bytes.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ use crate::{
2525
PyResult, PyValue, TryFromObject, TypeProtocol,
2626
};
2727

28-
use crate::builtins::memory::{Buffer, BufferOptions};
28+
use crate::builtins::memory::{BufferOptions, PyBuffer};
2929

3030
/// "bytes(iterable_of_ints) -> bytes\n\
3131
/// bytes(string, encoding[, errors]) -> bytes\n\
@@ -495,7 +495,7 @@ impl PyBytes {
495495
}
496496

497497
impl BufferProtocol for PyBytes {
498-
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
498+
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn PyBuffer>> {
499499
let buf = BytesBuffer {
500500
bytes: zelf.clone(),
501501
options: BufferOptions {
@@ -513,7 +513,7 @@ struct BytesBuffer {
513513
options: BufferOptions,
514514
}
515515

516-
impl Buffer for BytesBuffer {
516+
impl PyBuffer for BytesBuffer {
517517
fn obj_bytes(&self) -> BorrowedValue<[u8]> {
518518
self.bytes.as_bytes().into()
519519
}

vm/src/builtins/memory.rs

Lines changed: 47 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -15,50 +15,67 @@ use crate::sliceable::{convert_slice, saturate_range, wrap_index, SequenceIndex}
1515
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp};
1616
use crate::stdlib::pystruct::_struct::FormatSpec;
1717
use crate::utils::Either;
18-
use crate::VirtualMachine;
1918
use crate::{
2019
IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyObjectRef, PyRef,
2120
PyResult, PyThreadingConstraint, PyValue, TypeProtocol,
2221
};
22+
use crate::{TryFromObject, VirtualMachine};
2323
use crossbeam_utils::atomic::AtomicCell;
2424
use itertools::Itertools;
2525
use num_bigint::BigInt;
2626
use num_traits::{One, Signed, ToPrimitive, Zero};
2727

2828
#[derive(Debug)]
29-
pub struct BufferRef(Box<dyn Buffer>);
30-
impl Drop for BufferRef {
29+
pub struct PyBufferRef(Box<dyn PyBuffer>);
30+
31+
impl TryFromObject for PyBufferRef {
32+
// FIXME: `obj: &PyObjectRef` is enough
33+
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
34+
let obj_cls = obj.class();
35+
for cls in obj_cls.iter_mro() {
36+
if let Some(f) = cls.slots.as_buffer.as_ref() {
37+
return f(&obj, vm).map(|x| PyBufferRef(x));
38+
}
39+
}
40+
Err(vm.new_type_error(format!(
41+
"a bytes-like object is required, not '{}'",
42+
obj_cls.name
43+
)))
44+
}
45+
}
46+
47+
impl Drop for PyBufferRef {
3148
fn drop(&mut self) {
3249
self.0.release();
3350
}
3451
}
35-
impl Deref for BufferRef {
36-
type Target = dyn Buffer;
52+
impl Deref for PyBufferRef {
53+
type Target = dyn PyBuffer;
3754

3855
fn deref(&self) -> &Self::Target {
3956
self.0.deref()
4057
}
4158
}
42-
impl BufferRef {
43-
pub fn new(buffer: impl Buffer + 'static) -> Self {
59+
impl PyBufferRef {
60+
pub fn new(buffer: impl PyBuffer + 'static) -> Self {
4461
Self(Box::new(buffer))
4562
}
4663
pub fn into_rcbuf(self) -> RcBuffer {
47-
// move self.0 out of self; BufferRef impls Drop so it's tricky
64+
// move self.0 out of self; PyBufferRef impls Drop so it's tricky
4865
let this = std::mem::ManuallyDrop::new(self);
4966
let buf_box = unsafe { std::ptr::read(&this.0) };
5067
RcBuffer(buf_box.into())
5168
}
5269
}
53-
impl From<Box<dyn Buffer>> for BufferRef {
54-
fn from(buffer: Box<dyn Buffer>) -> Self {
55-
BufferRef(buffer)
70+
impl From<Box<dyn PyBuffer>> for PyBufferRef {
71+
fn from(buffer: Box<dyn PyBuffer>) -> Self {
72+
PyBufferRef(buffer)
5673
}
5774
}
5875
#[derive(Debug, Clone)]
59-
pub struct RcBuffer(PyRc<dyn Buffer>);
76+
pub struct RcBuffer(PyRc<dyn PyBuffer>);
6077
impl Deref for RcBuffer {
61-
type Target = dyn Buffer;
78+
type Target = dyn PyBuffer;
6279
fn deref(&self) -> &Self::Target {
6380
self.0.deref()
6481
}
@@ -71,7 +88,7 @@ impl Drop for RcBuffer {
7188
}
7289
}
7390
}
74-
impl Buffer for RcBuffer {
91+
impl PyBuffer for RcBuffer {
7592
fn get_options(&self) -> &BufferOptions {
7693
self.0.get_options()
7794
}
@@ -93,7 +110,7 @@ impl Buffer for RcBuffer {
93110
}
94111
}
95112

96-
pub trait Buffer: Debug + PyThreadingConstraint {
113+
pub trait PyBuffer: Debug + PyThreadingConstraint {
97114
fn get_options(&self) -> &BufferOptions;
98115
/// Get the full inner buffer of this memory. You probably want [`as_contiguous()`], as
99116
/// `obj_bytes` doesn't take into account the range a memoryview might operate on, among other
@@ -171,7 +188,7 @@ struct PyMemoryViewNewArgs {
171188
#[derive(Debug)]
172189
pub struct PyMemoryView {
173190
obj: PyObjectRef,
174-
buffer: BufferRef,
191+
buffer: PyBufferRef,
175192
options: BufferOptions,
176193
pub(crate) released: AtomicCell<bool>,
177194
// start should always less or equal to the stop
@@ -195,7 +212,11 @@ impl PyMemoryView {
195212
.map_err(|msg| vm.new_exception_msg(vm.ctx.types.memoryview_type.clone(), msg))
196213
}
197214

198-
pub fn from_buffer(obj: PyObjectRef, buffer: BufferRef, vm: &VirtualMachine) -> PyResult<Self> {
215+
pub fn from_buffer(
216+
obj: PyObjectRef,
217+
buffer: PyBufferRef,
218+
vm: &VirtualMachine,
219+
) -> PyResult<Self> {
199220
// when we get a buffer means the buffered object is size locked
200221
// so we can assume the buffer's options will never change as long
201222
// as memoryview is still alive
@@ -219,7 +240,7 @@ impl PyMemoryView {
219240

220241
pub fn from_buffer_range(
221242
obj: PyObjectRef,
222-
buffer: BufferRef,
243+
buffer: PyBufferRef,
223244
range: std::ops::Range<usize>,
224245
vm: &VirtualMachine,
225246
) -> PyResult<Self> {
@@ -256,7 +277,7 @@ impl PyMemoryView {
256277
args: PyMemoryViewNewArgs,
257278
vm: &VirtualMachine,
258279
) -> PyResult<PyRef<Self>> {
259-
let buffer = try_buffer_from_object(vm, &args.object)?;
280+
let buffer = PyBufferRef::try_from_object(vm, args.object.clone())?;
260281
let zelf = PyMemoryView::from_buffer(args.object, buffer, vm)?;
261282
zelf.into_ref_with_type(vm, cls)
262283
}
@@ -373,7 +394,7 @@ impl PyMemoryView {
373394
let itemsize = zelf.options.itemsize;
374395

375396
let obj = zelf.obj.clone();
376-
let buffer = BufferRef(Box::new(zelf.clone()));
397+
let buffer = PyBufferRef(Box::new(zelf.clone()));
377398
zelf.exports.fetch_add(1);
378399
let options = zelf.options.clone();
379400
let format_spec = zelf.format_spec.clone();
@@ -517,7 +538,7 @@ impl PyMemoryView {
517538
items: PyObjectRef,
518539
vm: &VirtualMachine,
519540
) -> PyResult<()> {
520-
let items = try_buffer_from_object(vm, &items)?;
541+
let items = PyBufferRef::try_from_object(vm, items)?;
521542
let options = items.get_options();
522543
let len = options.len;
523544
let itemsize = options.itemsize;
@@ -660,7 +681,7 @@ impl PyMemoryView {
660681
#[pymethod]
661682
fn toreadonly(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
662683
zelf.try_not_released(vm)?;
663-
let buffer = BufferRef(Box::new(zelf.clone()));
684+
let buffer = PyBufferRef(Box::new(zelf.clone()));
664685
zelf.exports.fetch_add(1);
665686
Ok(PyMemoryView {
666687
obj: zelf.obj.clone(),
@@ -731,7 +752,7 @@ impl PyMemoryView {
731752
);
732753
}
733754

734-
let buffer = BufferRef(Box::new(zelf.clone()));
755+
let buffer = PyBufferRef(Box::new(zelf.clone()));
735756
zelf.exports.fetch_add(1);
736757

737758
Ok(PyMemoryView {
@@ -761,7 +782,7 @@ impl PyMemoryView {
761782
return Ok(false);
762783
}
763784

764-
let other = match try_buffer_from_object(vm, other) {
785+
let other = match PyBufferRef::try_from_object(vm, other.clone()) {
765786
Ok(buf) => buf,
766787
Err(_) => return Ok(false),
767788
};
@@ -829,7 +850,7 @@ impl Drop for PyMemoryView {
829850
}
830851

831852
impl BufferProtocol for PyMemoryView {
832-
fn get_buffer(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
853+
fn get_buffer(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn PyBuffer>> {
833854
if zelf.released.load() {
834855
Err(vm.new_value_error("operation forbidden on released memoryview object".to_owned()))
835856
} else {
@@ -838,7 +859,7 @@ impl BufferProtocol for PyMemoryView {
838859
}
839860
}
840861

841-
impl Buffer for PyMemoryViewRef {
862+
impl PyBuffer for PyMemoryViewRef {
842863
fn get_options(&self) -> &BufferOptions {
843864
&self.options
844865
}
@@ -940,19 +961,6 @@ pub(crate) fn init(ctx: &PyContext) {
940961
PyMemoryView::extend_class(ctx, &ctx.types.memoryview_type)
941962
}
942963

943-
pub fn try_buffer_from_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<BufferRef> {
944-
let obj_cls = obj.class();
945-
for cls in obj_cls.iter_mro() {
946-
if let Some(f) = cls.slots.buffer.as_ref() {
947-
return f(obj, vm).map(|x| BufferRef(x));
948-
}
949-
}
950-
Err(vm.new_type_error(format!(
951-
"a bytes-like object is required, not '{}'",
952-
obj_cls.name
953-
)))
954-
}
955-
956964
fn format_unpack(
957965
format_spec: &FormatSpec,
958966
bytes: &[u8],

vm/src/byteslike.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
use crate::builtins::memory::{try_buffer_from_object, BufferRef};
1+
use crate::builtins::memory::PyBufferRef;
22
use crate::builtins::PyStrRef;
33
use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
44
use crate::vm::VirtualMachine;
55
use crate::{PyObjectRef, PyResult, TryFromObject};
66

77
#[derive(Debug)]
8-
pub struct PyBytesLike(BufferRef);
8+
pub struct PyBytesLike(PyBufferRef);
99

1010
#[derive(Debug)]
11-
pub struct PyRwBytesLike(BufferRef);
11+
pub struct PyRwBytesLike(PyBufferRef);
1212

1313
impl PyBytesLike {
1414
pub fn with_ref<F, R>(&self, f: F) -> R
@@ -50,15 +50,15 @@ impl PyRwBytesLike {
5050

5151
impl PyBytesLike {
5252
pub fn new(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Self> {
53-
let buffer = try_buffer_from_object(vm, obj)?;
53+
let buffer = PyBufferRef::try_from_object(vm, obj.clone())?;
5454
if buffer.get_options().contiguous {
5555
Ok(Self(buffer))
5656
} else {
5757
Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()))
5858
}
5959
}
6060

61-
pub fn into_buffer(self) -> BufferRef {
61+
pub fn into_buffer(self) -> PyBufferRef {
6262
self.0
6363
}
6464

@@ -78,7 +78,7 @@ pub fn try_bytes_like<R>(
7878
obj: &PyObjectRef,
7979
f: impl FnOnce(&[u8]) -> R,
8080
) -> PyResult<R> {
81-
let buffer = try_buffer_from_object(vm, obj)?;
81+
let buffer = PyBufferRef::try_from_object(vm, obj.clone())?;
8282
buffer.as_contiguous().map(|x| f(&*x)).ok_or_else(|| {
8383
vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned())
8484
})
@@ -89,7 +89,7 @@ pub fn try_rw_bytes_like<R>(
8989
obj: &PyObjectRef,
9090
f: impl FnOnce(&mut [u8]) -> R,
9191
) -> PyResult<R> {
92-
let buffer = try_buffer_from_object(vm, obj)?;
92+
let buffer = PyBufferRef::try_from_object(vm, obj.clone())?;
9393
buffer
9494
.as_contiguous_mut()
9595
.map(|mut x| f(&mut *x))
@@ -98,7 +98,7 @@ pub fn try_rw_bytes_like<R>(
9898

9999
impl PyRwBytesLike {
100100
pub fn new(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Self> {
101-
let buffer = try_buffer_from_object(vm, obj)?;
101+
let buffer = PyBufferRef::try_from_object(vm, obj.clone())?;
102102
let options = buffer.get_options();
103103
if !options.contiguous {
104104
Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()))
@@ -109,7 +109,7 @@ impl PyRwBytesLike {
109109
}
110110
}
111111

112-
pub fn into_buffer(self) -> BufferRef {
112+
pub fn into_buffer(self) -> PyBufferRef {
113113
self.0
114114
}
115115

vm/src/cformat.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@
22
/// [https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting]
33
use crate::builtins::float::{try_bigint, IntoPyFloat, PyFloat};
44
use crate::builtins::int::{self, PyInt};
5+
use crate::builtins::memory::PyBufferRef;
56
use crate::builtins::pystr::PyStr;
6-
use crate::builtins::{memory::try_buffer_from_object, tuple, PyBytes};
7+
use crate::builtins::{tuple, PyBytes};
78
use crate::common::float_ops;
89
use crate::vm::VirtualMachine;
910
use crate::{ItemProtocol, PyObjectRef, PyResult, TryFromObject, TypeProtocol};
@@ -363,7 +364,7 @@ impl CFormatSpec {
363364
Ok(s.into_bytes())
364365
}
365366
CFormatPreconversor::Str | CFormatPreconversor::Bytes => {
366-
if let Ok(buffer) = try_buffer_from_object(vm, &obj) {
367+
if let Ok(buffer) = PyBufferRef::try_from_object(vm, obj.clone()) {
367368
let guard;
368369
let vec;
369370
let bytes = match buffer.as_contiguous() {

0 commit comments

Comments
 (0)