forked from RustPython/RustPython
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathbuffer.rs
More file actions
139 lines (124 loc) · 3.7 KB
/
buffer.rs
File metadata and controls
139 lines (124 loc) · 3.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
//! Buffer protocol
use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
use crate::common::rc::PyRc;
use crate::PyThreadingConstraint;
use crate::{PyObjectRef, PyResult, TryFromBorrowedObject, TypeProtocol, VirtualMachine};
use std::{borrow::Cow, fmt::Debug};
pub trait PyBufferInternal: Debug + PyThreadingConstraint {
/// Get the full inner buffer of this memory. You probably want [`as_contiguous()`], as
/// `obj_bytes` doesn't take into account the range a memoryview might operate on, among other
/// footguns.
fn obj_bytes(&self) -> BorrowedValue<[u8]>;
/// Get the full inner buffer of this memory, mutably. You probably want
/// [`as_contiguous_mut()`], as `obj_bytes` doesn't take into account the range a memoryview
/// might operate on, among other footguns.
fn obj_bytes_mut(&self) -> BorrowedValueMut<[u8]>;
fn release(&self);
// not included in PyBuffer protocol itself
fn retain(&self);
}
#[derive(Debug)]
pub struct PyBuffer {
pub obj: PyObjectRef,
pub options: BufferOptions,
pub(crate) internal: PyRc<dyn PyBufferInternal>,
}
impl PyBuffer {
pub fn new(
obj: PyObjectRef,
buffer: impl PyBufferInternal + 'static,
options: BufferOptions,
) -> Self {
buffer.retain();
Self {
obj,
options,
internal: PyRc::new(buffer),
}
}
pub fn as_contiguous(&self) -> Option<BorrowedValue<[u8]>> {
if !self.options.contiguous {
return None;
}
Some(self.internal.obj_bytes())
}
pub fn as_contiguous_mut(&self) -> Option<BorrowedValueMut<[u8]>> {
if !self.options.contiguous {
return None;
}
Some(self.internal.obj_bytes_mut())
}
pub fn to_contiguous(&self) -> Vec<u8> {
self.internal.obj_bytes().to_vec()
}
pub fn clone_with_options(&self, options: BufferOptions) -> Self {
self.internal.retain();
Self {
obj: self.obj.clone(),
options,
internal: self.internal.clone(),
}
}
}
#[derive(Debug, Clone)]
pub struct BufferOptions {
// buf
pub len: usize,
pub readonly: bool,
pub itemsize: usize,
pub format: Cow<'static, str>,
pub ndim: usize, // TODO: support multiple dimension array
pub shape: Vec<usize>,
pub strides: Vec<isize>,
// suboffsets
// RustPython fields
pub contiguous: bool,
}
impl BufferOptions {
pub const DEFAULT: Self = BufferOptions {
len: 0,
readonly: true,
itemsize: 1,
format: Cow::Borrowed("B"),
ndim: 1,
shape: Vec::new(),
strides: Vec::new(),
contiguous: true,
};
}
impl Default for BufferOptions {
fn default() -> Self {
Self::DEFAULT
}
}
impl TryFromBorrowedObject for PyBuffer {
fn try_from_borrowed_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<Self> {
let obj_cls = obj.class();
for cls in obj_cls.iter_mro() {
if let Some(f) = cls.slots.as_buffer.as_ref() {
return f(obj, vm);
}
}
Err(vm.new_type_error(format!(
"a bytes-like object is required, not '{}'",
obj_cls.name()
)))
}
}
// What we actually want to implement is:
// impl<T> Drop for T where T: PyBufferInternal
// but it is not supported by Rust
impl Drop for PyBuffer {
fn drop(&mut self) {
self.internal.release();
}
}
impl Clone for PyBuffer {
fn clone(&self) -> Self {
self.clone_with_options(self.options.clone())
}
}
pub(crate) trait ResizeGuard<'a> {
type Resizable: 'a;
fn try_resizable(&'a self, vm: &VirtualMachine) -> PyResult<Self::Resizable>;
}