Skip to content

Commit 888b382

Browse files
committed
Give a sole module for buffer protocol
1 parent 93cf687 commit 888b382

File tree

11 files changed

+193
-183
lines changed

11 files changed

+193
-183
lines changed

vm/src/buffer.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
//! Buffer protocol
2+
3+
use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
4+
use crate::common::rc::PyRc;
5+
use crate::PyThreadingConstraint;
6+
use crate::{PyObjectRef, PyResult, TypeProtocol};
7+
use crate::{TryFromBorrowedObject, VirtualMachine};
8+
use std::{borrow::Cow, fmt::Debug, ops::Deref};
9+
10+
pub trait PyBuffer: Debug + PyThreadingConstraint {
11+
fn get_options(&self) -> &BufferOptions;
12+
/// Get the full inner buffer of this memory. You probably want [`as_contiguous()`], as
13+
/// `obj_bytes` doesn't take into account the range a memoryview might operate on, among other
14+
/// footguns.
15+
fn obj_bytes(&self) -> BorrowedValue<[u8]>;
16+
/// Get the full inner buffer of this memory, mutably. You probably want
17+
/// [`as_contiguous_mut()`], as `obj_bytes` doesn't take into account the range a memoryview
18+
/// might operate on, among other footguns.
19+
fn obj_bytes_mut(&self) -> BorrowedValueMut<[u8]>;
20+
fn release(&self);
21+
22+
fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> {
23+
if !self.get_options().contiguous {
24+
return None;
25+
}
26+
Some(self.obj_bytes())
27+
}
28+
29+
fn as_contiguous_mut(&self) -> Option<BorrowedValueMut<[u8]>> {
30+
if !self.get_options().contiguous {
31+
return None;
32+
}
33+
Some(self.obj_bytes_mut())
34+
}
35+
36+
fn to_contiguous(&self) -> Vec<u8> {
37+
self.obj_bytes().to_vec()
38+
}
39+
}
40+
41+
#[derive(Debug, Clone)]
42+
pub struct BufferOptions {
43+
pub readonly: bool,
44+
pub len: usize,
45+
pub itemsize: usize,
46+
pub contiguous: bool,
47+
pub format: Cow<'static, str>,
48+
// TODO: support multiple dimension array
49+
pub ndim: usize,
50+
pub shape: Vec<usize>,
51+
pub strides: Vec<isize>,
52+
}
53+
54+
impl BufferOptions {
55+
pub const DEFAULT: Self = BufferOptions {
56+
readonly: true,
57+
len: 0,
58+
itemsize: 1,
59+
contiguous: true,
60+
format: Cow::Borrowed("B"),
61+
ndim: 1,
62+
shape: Vec::new(),
63+
strides: Vec::new(),
64+
};
65+
}
66+
67+
impl Default for BufferOptions {
68+
fn default() -> Self {
69+
Self::DEFAULT
70+
}
71+
}
72+
73+
#[derive(Debug)]
74+
pub struct PyBufferRef(Box<dyn PyBuffer>);
75+
76+
impl TryFromBorrowedObject for PyBufferRef {
77+
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Self> {
78+
let obj_cls = obj.class();
79+
for cls in obj_cls.iter_mro() {
80+
if let Some(f) = cls.slots.as_buffer.as_ref() {
81+
return f(obj, vm).map(|x| PyBufferRef(x));
82+
}
83+
}
84+
Err(vm.new_type_error(format!(
85+
"a bytes-like object is required, not '{}'",
86+
obj_cls.name
87+
)))
88+
}
89+
}
90+
91+
impl Drop for PyBufferRef {
92+
fn drop(&mut self) {
93+
self.0.release();
94+
}
95+
}
96+
97+
impl Deref for PyBufferRef {
98+
type Target = dyn PyBuffer;
99+
100+
fn deref(&self) -> &Self::Target {
101+
self.0.deref()
102+
}
103+
}
104+
105+
impl PyBufferRef {
106+
pub fn new(buffer: impl PyBuffer + 'static) -> Self {
107+
Self(Box::new(buffer))
108+
}
109+
110+
pub fn into_rcbuf(self) -> RcBuffer {
111+
// move self.0 out of self; PyBufferRef impls Drop so it's tricky
112+
let this = std::mem::ManuallyDrop::new(self);
113+
let buf_box = unsafe { std::ptr::read(&this.0) };
114+
RcBuffer(buf_box.into())
115+
}
116+
}
117+
118+
impl From<Box<dyn PyBuffer>> for PyBufferRef {
119+
fn from(buffer: Box<dyn PyBuffer>) -> Self {
120+
PyBufferRef(buffer)
121+
}
122+
}
123+
124+
#[derive(Debug, Clone)]
125+
pub struct RcBuffer(PyRc<dyn PyBuffer>);
126+
impl Deref for RcBuffer {
127+
type Target = dyn PyBuffer;
128+
fn deref(&self) -> &Self::Target {
129+
self.0.deref()
130+
}
131+
}
132+
133+
impl Drop for RcBuffer {
134+
fn drop(&mut self) {
135+
// check if this is the last rc before the inner buffer gets dropped
136+
if let Some(buf) = PyRc::get_mut(&mut self.0) {
137+
buf.release()
138+
}
139+
}
140+
}
141+
142+
impl PyBuffer for RcBuffer {
143+
fn get_options(&self) -> &BufferOptions {
144+
self.0.get_options()
145+
}
146+
fn obj_bytes(&self) -> BorrowedValue<[u8]> {
147+
self.0.obj_bytes()
148+
}
149+
fn obj_bytes_mut(&self) -> BorrowedValueMut<[u8]> {
150+
self.0.obj_bytes_mut()
151+
}
152+
fn release(&self) {}
153+
fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> {
154+
self.0.as_contiguous()
155+
}
156+
fn as_contiguous_mut(&self) -> Option<BorrowedValueMut<[u8]>> {
157+
self.0.as_contiguous_mut()
158+
}
159+
fn to_contiguous(&self) -> Vec<u8> {
160+
self.0.to_contiguous()
161+
}
162+
}
163+
164+
pub(crate) trait ResizeGuard<'a> {
165+
type Resizable: 'a;
166+
fn try_resizable(&'a self, vm: &VirtualMachine) -> PyResult<Self::Resizable>;
167+
}

vm/src/builtins/bytearray.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
use super::bytes::{PyBytes, PyBytesRef};
33
use super::dict::PyDictRef;
44
use super::int::PyIntRef;
5-
use super::memory::{BufferOptions, PyBuffer, ResizeGuard};
65
use super::pystr::PyStrRef;
76
use super::pytype::PyTypeRef;
87
use super::tuple::PyTupleRef;
98
use crate::anystr::{self, AnyStr};
9+
use crate::buffer::{BufferOptions, PyBuffer, ResizeGuard};
1010
use crate::bytesinner::{
1111
bytes_decode, bytes_from_object, value_from_object, ByteInnerFindOptions, ByteInnerNewOptions,
1212
ByteInnerPaddingOptions, ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs,

vm/src/builtins/bytes.rs

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
1-
use bstr::ByteSlice;
2-
use crossbeam_utils::atomic::AtomicCell;
3-
use rustpython_common::borrow::{BorrowedValue, BorrowedValueMut};
4-
use std::mem::size_of;
5-
use std::ops::Deref;
6-
71
use super::dict::PyDictRef;
82
use super::int::PyIntRef;
93
use super::pystr::PyStrRef;
104
use super::pytype::PyTypeRef;
115
use crate::anystr::{self, AnyStr};
6+
use crate::buffer::{BufferOptions, PyBuffer};
127
use crate::builtins::tuple::PyTupleRef;
138
use crate::bytesinner::{
149
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
@@ -24,8 +19,11 @@ use crate::{
2419
IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext, PyIterable, PyObjectRef,
2520
PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
2621
};
27-
28-
use crate::builtins::memory::{BufferOptions, PyBuffer};
22+
use bstr::ByteSlice;
23+
use crossbeam_utils::atomic::AtomicCell;
24+
use rustpython_common::borrow::{BorrowedValue, BorrowedValueMut};
25+
use std::mem::size_of;
26+
use std::ops::Deref;
2927

3028
/// "bytes(iterable_of_ints) -> bytes\n\
3129
/// bytes(string, encoding[, errors]) -> bytes\n\

0 commit comments

Comments
 (0)