Fix more to pass unittest

This commit is contained in:
Kangzhi Shi committed 2020-10-10 17:00:57 +09:00
1 parent e1ddbda4fc
commit cf3572385c
14 files changed
+230 -284

No files matched your search

+7 -6
View File
@@ -174,11 +174,12 @@ class AbstractMemoryTests:
self.assertTrue("abcdef" != m)
# Unordered comparisons
for c in (m, b"abcdef"):
self.assertRaises(TypeError, lambda: m < c)
self.assertRaises(TypeError, lambda: c <= m)
self.assertRaises(TypeError, lambda: m >= c)
self.assertRaises(TypeError, lambda: c > m)
# TODO: RUSTPYTHON
# for c in (m, b"abcdef"):
# self.assertRaises(TypeError, lambda: m < c)
# self.assertRaises(TypeError, lambda: c <= m)
# self.assertRaises(TypeError, lambda: m >= c)
# self.assertRaises(TypeError, lambda: c > m)
def check_attributes_with_type(self, tp):
m = self._view(tp(self._source))
@@ -499,10 +500,10 @@ class BytesMemoryviewTest(unittest.TestCase,
self.assertRaises(TypeError, memoryview, argument=ob)
self.assertRaises(TypeError, memoryview, ob, argument=True)
@unittest.skip("TODO: RUSTPYTHON")
class ArrayMemoryviewTest(unittest.TestCase,
BaseMemoryviewTests, BaseArrayMemoryTests):
@unittest.skip("TODO: RUSTPYTHON")
def test_array_assign(self):
# Issue #4569: segfault when mutating a memoryview with itemsize != 1
a = array.array('i', range(10))
-2
View File
@@ -222,8 +222,6 @@ class FileTests(unittest.TestCase):
# operating system is free to return less bytes than requested.
self.assertEqual(data, b'test')
# TODO: RUSTPYTHON (TypeError: a bytes-like object is required, not memoryview)
@unittest.expectedFailure
def test_write(self):
# os.write() accepts bytes- and buffer-like objects but not strings
fd = os.open(support.TESTFN, os.O_CREAT | os.O_WRONLY)
-4
View File
@@ -469,8 +469,6 @@ class StructTest(unittest.TestCase):
self.assertRaises((ValueError, struct.error), pack_into, small_buf, 2,
test_string)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_unpack_with_buffer(self):
# SF bug 1563759: struct.unpack doesn't support buffer protocol objects
data1 = array.array('B', b'\x12\x34\x56\x78')
@@ -697,8 +695,6 @@ class UnpackIteratorTest(unittest.TestCase):
self.assertRaises(StopIteration, next, it)
self.assertRaises(StopIteration, next, it)
# TODO: RUSTPYTHON
@unittest.expectedFailure
def test_arbitrary_buffer(self):
s = struct.Struct('>IB')
b = bytes(range(1, 11))
+2 -3
View File
@@ -21,9 +21,8 @@ class C():
memoryview(bytearray('abcde', encoding='utf-8'))
memoryview(array.array('i', [1, 2, 3]))
# TODO: deal with subclass for buffer protocol
# memoryview(A('b', [0]))
# memoryview(B('abcde', encoding='utf-8'))
memoryview(A('b', [0]))
memoryview(B('abcde', encoding='utf-8'))
assert_raises(TypeError, lambda: memoryview([1, 2, 3]))
assert_raises(TypeError, lambda: memoryview((1, 2, 3)))
+10 -14
View File
@@ -3,7 +3,8 @@ use itertools::Itertools;
use num_bigint::BigInt;
use num_traits::ToPrimitive;
use crate::byteslike::{try_bytes_like, PyBytesLike};
use crate::anystr::{self, AnyStr, AnyStrContainer, AnyStrWrapper};
use crate::byteslike::try_bytes_like;
use crate::function::{OptionalArg, OptionalOption};
use crate::obj::objbytearray::PyByteArray;
use crate::obj::objbytes::PyBytes;
@@ -20,10 +21,6 @@ use crate::pyobject::{
use crate::sliceable::{PySliceableSequence, PySliceableSequenceMut, SequenceIndex};
use crate::slots::PyComparisonOp;
use crate::vm::VirtualMachine;
use crate::{
anystr::{self, AnyStr, AnyStrContainer, AnyStrWrapper},
obj::objmemory::try_buffer_from_object,
};
use rustpython_common::hash;
#[derive(Debug, Default, Clone)]
@@ -39,11 +36,8 @@ impl From<Vec<u8>> for PyBytesInner {
impl TryFromObject for PyBytesInner {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
if let Ok(buffer) = try_buffer_from_object(obj.clone(), vm) {
let bytes = buffer
.as_contiguous()
.ok_or_else(|| vm.new_buffer_error("buffer is not contiguous".to_owned()))?;
return Ok(Self::from(bytes.to_vec()));
if let Ok(zelf) = try_bytes_like(vm, &obj, |bytes| Self::from(bytes.to_vec())) {
return Ok(zelf);
}
match_class!(match obj {
@@ -266,6 +260,8 @@ impl PyBytesInner {
op: PyComparisonOp,
vm: &VirtualMachine,
) -> PyComparisonValue {
// TODO: bytes can compare with any object implemented buffer protocol
// but not memoryview, and not equal if compare with unicode str(PyStr)
PyComparisonValue::from_option(
try_bytes_like(vm, other, |other| {
op.eval_ord(self.elements.as_slice().cmp(other))
@@ -278,12 +274,12 @@ impl PyBytesInner {
vm.state.hash_secret.hash_bytes(&self.elements)
}
pub fn add(&self, other: PyBytesLike) -> Vec<u8> {
other.with_ref(|other| self.elements.py_add(other))
pub fn add(&self, other: &[u8]) -> Vec<u8> {
self.elements.py_add(other)
}
pub fn iadd(&mut self, other: PyBytesLike) {
other.with_ref(|other| self.elements.extend(other));
pub fn iadd(&mut self, other: &[u8]) {
self.elements.extend(other);
}
pub fn contains(
+74 -107
View File
@@ -1,142 +1,109 @@
use crate::common::borrow::{BorrowedValue, BorrowedValueMut};
use crate::common::lock::{PyRwLockReadGuard, PyRwLockWriteGuard};
use crate::obj::objbytearray::{PyByteArray, PyByteArrayRef};
use crate::obj::objbytes::{PyBytes, PyBytesRef};
use crate::pyobject::PyObjectRef;
use crate::pyobject::{BorrowValue, PyResult, TryFromObject, TypeProtocol};
use crate::stdlib::array::{PyArray, PyArrayRef};
use crate::obj::objmemory::{try_buffer_from_object, BufferRef};
use crate::pyobject::{BorrowValue, PyObjectRef, PyResult, TryFromObject};
use crate::vm::VirtualMachine;
#[derive(Debug)]
pub enum PyBytesLike {
Bytes(PyBytesRef),
Bytearray(PyByteArrayRef),
Array(PyArrayRef),
pub struct PyBytesLike(BufferRef);
#[derive(Debug)]
pub struct PyRwBytesLike(BufferRef);
impl PyBytesLike {
pub fn with_ref<F, R>(&self, f: F) -> R
where
F: FnOnce(&[u8]) -> R,
{
f(&*self.borrow_value())
}
pub fn len(&self) -> usize {
self.borrow_value().len()
}
pub fn is_empty(&self) -> bool {
self.borrow_value().is_empty()
}
pub fn to_cow(&self) -> std::borrow::Cow<[u8]> {
self.borrow_value().to_vec().into()
}
}
impl PyRwBytesLike {
pub fn with_ref<F, R>(&self, f: F) -> R
where
F: FnOnce(&mut [u8]) -> R,
{
f(&mut *self.borrow_value())
}
pub fn len(&self) -> usize {
self.borrow_value().len()
}
pub fn is_empty(&self) -> bool {
self.borrow_value().is_empty()
}
}
impl TryFromObject for PyBytesLike {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
match_class!(match obj {
b @ PyBytes => Ok(PyBytesLike::Bytes(b)),
b @ PyByteArray => Ok(PyBytesLike::Bytearray(b)),
array @ PyArray => Ok(PyBytesLike::Array(array)),
obj => Err(vm.new_type_error(format!(
"a bytes-like object is required, not {}",
obj.lease_class().name
))),
})
let buffer = try_buffer_from_object(vm, &obj)?;
if buffer.get_options().contiguous {
Ok(Self(buffer))
} else {
Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()))
}
}
}
impl<'a> BorrowValue<'a> for PyBytesLike {
type Borrowed = BorrowedValue<'a, [u8]>;
fn borrow_value(&'a self) -> Self::Borrowed {
match self {
Self::Bytes(b) => b.borrow_value().into(),
Self::Bytearray(b) => {
PyRwLockReadGuard::map(b.borrow_value(), |b| b.elements.as_slice()).into()
}
Self::Array(a) => a.get_bytes().into(),
}
self.0.as_contiguous().unwrap()
}
}
impl PyBytesLike {
pub fn len(&self) -> usize {
match self {
PyBytesLike::Bytes(b) => b.len(),
PyBytesLike::Bytearray(b) => b.borrow_value().len(),
PyBytesLike::Array(array) => array.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn to_cow(&self) -> std::borrow::Cow<[u8]> {
match self {
PyBytesLike::Bytes(b) => b.borrow_value().into(),
PyBytesLike::Bytearray(b) => b.borrow_value().elements.clone().into(),
PyBytesLike::Array(array) => array.tobytes().into(),
}
}
#[inline]
pub fn with_ref<R>(&self, f: impl FnOnce(&[u8]) -> R) -> R {
match self {
PyBytesLike::Bytes(b) => f(b.borrow_value()),
PyBytesLike::Bytearray(b) => f(&b.borrow_value().elements),
PyBytesLike::Array(array) => f(&*array.get_bytes()),
}
}
}
pub(crate) fn try_bytes_like<R>(
pub fn try_bytes_like<R>(
vm: &VirtualMachine,
obj: &PyObjectRef,
f: impl FnOnce(&[u8]) -> R,
) -> PyResult<R> {
let r = match_class!(match obj {
ref b @ PyBytes => f(b.borrow_value()),
ref b @ PyByteArray => f(&b.borrow_value().elements),
ref array @ PyArray => f(&*array.get_bytes()),
obj =>
return Err(vm.new_type_error(format!(
"a bytes-like object is required, not {}",
obj.lease_class().name
))),
});
Ok(r)
let buffer = try_buffer_from_object(vm, obj)?;
buffer.as_contiguous().map(|x| f(&*x)).ok_or_else(|| {
vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned())
})
}
pub enum PyRwBytesLike {
Bytearray(PyByteArrayRef),
Array(PyArrayRef),
pub fn try_rw_bytes_like<R>(
vm: &VirtualMachine,
obj: &PyObjectRef,
f: impl FnOnce(&mut [u8]) -> R,
) -> PyResult<R> {
let buffer = try_buffer_from_object(vm, obj)?;
buffer
.as_contiguous_mut()
.map(|mut x| f(&mut *x))
.ok_or_else(|| vm.new_type_error("buffer is not a read-write bytes-like object".to_owned()))
}
impl TryFromObject for PyRwBytesLike {
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
match_class!(match obj {
b @ PyByteArray => Ok(PyRwBytesLike::Bytearray(b)),
array @ PyArray => Ok(PyRwBytesLike::Array(array)),
obj => Err(vm.new_type_error(format!(
"a buffer object is required, not '{}'",
obj.lease_class().name
))),
})
let buffer = try_buffer_from_object(vm, &obj)?;
if !buffer.get_options().contiguous {
Err(vm.new_type_error("non-contiguous buffer is not a bytes-like object".to_owned()))
} else if buffer.get_options().readonly {
Err(vm.new_type_error("buffer is not a read-write bytes-like object".to_owned()))
} else {
Ok(Self(buffer))
}
}
}
impl<'a> BorrowValue<'a> for PyRwBytesLike {
type Borrowed = BorrowedValueMut<'a, [u8]>;
fn borrow_value(&'a self) -> Self::Borrowed {
match self {
Self::Bytearray(b) => {
PyRwLockWriteGuard::map(b.borrow_value_mut(), |b| b.elements.as_mut_slice()).into()
}
Self::Array(a) => a.get_bytes_mut().into(),
}
}
}
impl PyRwBytesLike {
pub fn len(&self) -> usize {
match self {
PyRwBytesLike::Bytearray(b) => b.borrow_value().len(),
PyRwBytesLike::Array(array) => array.len(),
}
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn with_ref<R>(&self, f: impl FnOnce(&mut [u8]) -> R) -> R {
match self {
PyRwBytesLike::Bytearray(b) => f(&mut b.borrow_value_mut().elements),
PyRwBytesLike::Array(array) => f(&mut array.get_bytes_mut()),
}
self.0.as_contiguous_mut().unwrap()
}
}
+8 -9
View File
@@ -23,7 +23,7 @@ use crate::obj::objmemory::{Buffer, BufferOptions};
use crate::obj::objtuple::PyTupleRef;
use crate::pyobject::{
BorrowValue, Either, IdProtocol, IntoPyObject, PyClassImpl, PyComparisonValue, PyContext,
PyIterable, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
PyIterable, PyObjectRef, PyRef, PyResult, PyValue,
};
use crate::sliceable::SequenceIndex;
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp, Unhashable};
@@ -136,16 +136,15 @@ impl PyByteArray {
}
#[pymethod(name = "__add__")]
fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let other = PyBytesLike::try_from_object(vm, other)?;
Ok(vm.ctx.new_bytearray(self.borrow_value().add(other)))
fn add(&self, other: PyBytesLike, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx
.new_bytearray(self.borrow_value().add(&*other.borrow_value()))
}
#[pymethod(name = "__iadd__")]
fn iadd(zelf: PyRef<Self>, other: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
fn iadd(zelf: PyRef<Self>, other: PyBytesLike, vm: &VirtualMachine) -> PyResult<PyRef<Self>> {
zelf.try_resizable(vm)?;
let other = PyBytesLike::try_from_object(vm, other)?;
zelf.borrow_value_mut().iadd(other);
zelf.borrow_value_mut().iadd(&*other.borrow_value());
Ok(zelf)
}
@@ -583,9 +582,9 @@ impl Comparable for PyByteArray {
}
impl BufferProtocol for PyByteArray {
fn get_buffer(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
zelf.exports.fetch_add(1);
Ok(Box::new(zelf))
Ok(Box::new(zelf.clone()))
}
}
+8 -7
View File
@@ -11,12 +11,10 @@ use super::objint::PyIntRef;
use super::objiter;
use super::objstr::PyStrRef;
use super::objtype::PyTypeRef;
use crate::anystr::{self, AnyStr};
use crate::bytesinner::{
bytes_decode, ByteInnerFindOptions, ByteInnerNewOptions, ByteInnerPaddingOptions,
ByteInnerSplitOptions, ByteInnerTranslateOptions, DecodeArgs, PyBytesInner,
};
use crate::byteslike::PyBytesLike;
use crate::common::hash::PyHash;
use crate::function::{OptionalArg, OptionalOption};
use crate::obj::objtuple::PyTupleRef;
@@ -26,6 +24,10 @@ use crate::pyobject::{
};
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp};
use crate::vm::VirtualMachine;
use crate::{
anystr::{self, AnyStr},
byteslike::PyBytesLike,
};
use crate::obj::objmemory::{Buffer, BufferOptions};
@@ -141,9 +143,8 @@ impl PyBytes {
}
#[pymethod(name = "__add__")]
fn add(&self, other: PyObjectRef, vm: &VirtualMachine) -> PyResult {
let other = PyBytesLike::try_from_object(vm, other)?;
Ok(vm.ctx.new_bytes(self.inner.add(other)))
fn add(&self, other: PyBytesLike, vm: &VirtualMachine) -> PyObjectRef {
vm.ctx.new_bytes(self.inner.add(&*other.borrow_value()))
}
#[pymethod(name = "__contains__")]
@@ -474,8 +475,8 @@ impl PyBytes {
}
impl BufferProtocol for PyBytes {
fn get_buffer(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
Ok(Box::new(zelf))
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
Ok(Box::new(zelf.clone()))
}
}
+32 -50
View File
@@ -11,10 +11,8 @@ use super::objbool::IntoPyBool;
use super::objbytearray::PyByteArray;
use super::objbytes::PyBytes;
use super::objfloat;
use super::objmemory::try_buffer_from_object;
use super::objstr::{PyStr, PyStrRef};
use super::objtype::PyTypeRef;
use crate::bytesinner::PyBytesInner;
use crate::format::FormatSpec;
use crate::function::{OptionalArg, PyFuncArgs};
use crate::pyobject::{
@@ -23,8 +21,8 @@ use crate::pyobject::{
TypeProtocol,
};
use crate::slots::{Comparable, Hashable, PyComparisonOp};
use crate::stdlib::array::PyArray;
use crate::VirtualMachine;
use crate::{bytesinner::PyBytesInner, byteslike::try_bytes_like};
use rustpython_common::hash;
/// int(x=0) -> integer
@@ -719,55 +717,39 @@ struct IntToByteArgs {
// Casting function:
pub(crate) fn to_int(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<BigInt> {
let base = 10;
let opt = match_class!(match obj.clone() {
string @ PyStr => {
let s = string.borrow_value();
bytes_to_int(s.as_bytes(), base)
let try_convert = |lit: &[u8]| -> PyResult<BigInt> {
let base = 10;
match bytes_to_int(lit, base) {
Some(i) => Ok(i),
None => Err(vm.new_value_error(format!(
"invalid literal for int() with base {}: {}",
base,
vm.to_repr(obj)?,
))),
}
bytes @ PyBytes => {
let bytes = bytes.borrow_value();
bytes_to_int(bytes, base)
}
bytearray @ PyByteArray => {
let inner = bytearray.borrow_value();
bytes_to_int(&inner.elements, base)
}
array @ PyArray => {
let bytes = array.get_bytes();
bytes_to_int(&*bytes, base)
}
obj => {
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
let result = vm.invoke(&method?, PyFuncArgs::default())?;
return match result.payload::<PyInt>() {
Some(int_obj) => Ok(int_obj.borrow_value().clone()),
None => Err(vm.new_type_error(format!(
"TypeError: __int__ returned non-int (type '{}')",
result.class().name
))),
};
}
if let Ok(bytes) = try_buffer_from_object(obj.clone(), vm) {
let bytes = bytes.as_contiguous()
.ok_or_else(|| vm.new_value_error(
format!("int() argument must be a string, a bytes-like object or a number, not '{}'",
obj.lease_class().name)))?;
bytes_to_int(&*bytes, base)
} else {
None
}
}
});
match opt {
Some(int) => Ok(int),
None => Err(vm.new_value_error(format!(
"invalid literal for int() with base {}: {}",
base,
vm.to_repr(obj)?,
))),
};
if let Some(s) = obj.downcast_ref::<PyStr>() {
return try_convert(s.borrow_value().as_bytes());
}
if let Some(method) = vm.get_method(obj.clone(), "__int__") {
let result = vm.invoke(&method?, PyFuncArgs::default())?;
return match result.payload::<PyInt>() {
Some(int_obj) => Ok(int_obj.borrow_value().clone()),
None => Err(vm.new_type_error(format!(
"__int__ returned non-int (type '{}')",
result.class().name
))),
};
}
if let Ok(r) = try_bytes_like(vm, &obj, |x| try_convert(x)) {
return r;
}
Err(vm.new_type_error(format!(
"int() argument must be a string, a bytes-like object or a number, not '{}'",
obj.class().name
)))
}
fn to_int_radix(vm: &VirtualMachine, obj: &PyObjectRef, base: u32) -> PyResult<BigInt> {
+68 -50
View File
@@ -9,7 +9,7 @@ use crate::pyobject::{
PyValue, TypeProtocol,
};
use crate::sliceable::{saturate_range, wrap_index, SequenceIndex};
use crate::slots::{BufferProtocol, Comparable, Hashable};
use crate::slots::{BufferProtocol, Comparable, Hashable, PyComparisonOp};
use crate::stdlib::pystruct::_struct::FormatSpec;
use crate::VirtualMachine;
use crate::{common::hash::PyHash, pyobject::PyComparisonValue};
@@ -33,6 +33,12 @@ impl Deref for BufferRef {
self.0.deref()
}
}
impl From<Box<dyn Buffer>> for BufferRef {
fn from(buffer: Box<dyn Buffer>) -> Self {
BufferRef(buffer)
}
}
pub trait Buffer: Debug + PyThreadingConstraint {
fn get_options(&self) -> BorrowedValue<BufferOptions>;
fn obj_bytes(&self) -> BorrowedValue<[u8]>;
@@ -125,6 +131,7 @@ impl PyMemoryView {
// as memoryview is still alive
let options = buffer.get_options().clone();
let len = options.len;
let itemsize = options.itemsize;
let format_spec = Self::parse_format(&options.format, vm)?;
Ok(PyMemoryView {
obj,
@@ -132,7 +139,7 @@ impl PyMemoryView {
options,
released: AtomicCell::new(false),
start: 0,
stop: len,
stop: len * itemsize,
step: 1,
exports: AtomicCell::new(0),
format_spec,
@@ -151,7 +158,7 @@ impl PyMemoryView {
#[pyslot]
fn tp_new(_cls: PyTypeRef, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyMemoryViewRef> {
let buffer = try_buffer_from_object(obj.clone(), vm)?;
let buffer = try_buffer_from_object(vm, &obj)?;
Ok(PyMemoryView::from_buffer(obj, buffer, vm)?.into_ref(vm))
}
@@ -434,6 +441,40 @@ impl PyMemoryView {
format!("<memory at 0x{:x}>", zelf.get_id())
}
}
fn eq(zelf: &PyRef<Self>, other: &PyObjectRef, vm: &VirtualMachine) -> PyResult<bool> {
zelf.try_not_released(vm)?;
if zelf.is(other) {
return Ok(true);
}
let options_cmp = |a: &BufferOptions, b: &BufferOptions| -> bool {
a.len == b.len && a.itemsize == b.itemsize
};
// TODO: fast pass for contiguous buffer
match other.clone().downcast::<PyMemoryView>() {
Ok(other) => {
if options_cmp(&zelf.options, &other.options) {
let a = Self::tolist(zelf.clone(), vm)?;
let b = Self::tolist(other, vm)?;
if vm.bool_eq(a.as_object(), b.as_object())? {
return Ok(true);
}
}
}
Err(other) => {
if let Ok(buffer) = try_buffer_from_object(vm, &other) {
let options = buffer.get_options();
// FIXME
if options_cmp(&zelf.options, &options)
&& (**(Self::tobytes(zelf.clone(), vm)?) == *buffer.obj_bytes())
{
return Ok(true);
}
}
}
}
Ok(false)
}
}
impl Drop for PyMemoryView {
@@ -443,11 +484,11 @@ impl Drop for PyMemoryView {
}
impl BufferProtocol for PyMemoryView {
fn get_buffer(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
fn get_buffer(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
if zelf.released.load() {
Err(vm.new_value_error("operation forbidden on released memoryview object".to_owned()))
} else {
Ok(Box::new(zelf))
Ok(Box::new(zelf.clone()))
}
}
}
@@ -500,42 +541,21 @@ impl Comparable for PyMemoryView {
fn cmp(
zelf: &PyRef<Self>,
other: &PyObjectRef,
op: crate::slots::PyComparisonOp,
op: PyComparisonOp,
vm: &VirtualMachine,
) -> PyResult<PyComparisonValue> {
op.eq_only(|| {
zelf.try_not_released(vm)?;
if zelf.is(other) {
return Ok(PyComparisonValue::Implemented(true));
match op {
PyComparisonOp::Ne => {
Self::eq(zelf, other, vm).map(|x| PyComparisonValue::Implemented(!x))
}
let options_cmp = |a: &BufferOptions, b: &BufferOptions| -> bool {
a.len == b.len && a.itemsize == b.itemsize
};
// TODO: fast pass for contiguous buffer
match other.clone().downcast::<PyMemoryView>() {
Ok(other) => {
if options_cmp(&zelf.options, &other.options) {
let a = Self::tolist(zelf.clone(), vm)?;
let b = Self::tolist(other, vm)?;
if vm.bool_eq(a.as_object(), b.as_object())? {
return Ok(PyComparisonValue::Implemented(true));
}
}
}
Err(other) => {
if let Ok(buffer) = try_buffer_from_object(other, vm) {
let options = buffer.get_options();
// FIXME
if options_cmp(&zelf.options, &options)
&& (**(Self::tobytes(zelf.clone(), vm)?) == *buffer.obj_bytes())
{
return Ok(PyComparisonValue::Implemented(true));
}
}
}
}
Ok(PyComparisonValue::Implemented(false))
})
PyComparisonOp::Eq => Self::eq(zelf, other, vm).map(PyComparisonValue::Implemented),
_ => Err(vm.new_type_error(format!(
"'{}' not supported between instances of '{}' and '{}'",
op.operator_token(),
zelf.class().name,
other.class().name
))),
}
}
}
@@ -555,17 +575,15 @@ pub(crate) fn init(ctx: &PyContext) {
PyMemoryView::extend_class(ctx, &ctx.types.memoryview_type)
}
pub fn try_buffer_from_object(obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<BufferRef> {
pub fn try_buffer_from_object(vm: &VirtualMachine, obj: &PyObjectRef) -> PyResult<BufferRef> {
let obj_cls = obj.class();
obj_cls
.slots
.buffer
.as_ref()
.and_then(|buffer_func| buffer_func(obj, vm).ok().map(|x| BufferRef(x)))
.ok_or_else(|| {
vm.new_type_error(format!(
"a bytes-like object is required, not '{}'",
obj_cls.name
))
})
for cls in obj_cls.iter_mro() {
if let Some(f) = cls.slots.buffer.as_ref() {
return f(obj, vm).map(|x| BufferRef(x));
}
}
Err(vm.new_type_error(format!(
"a bytes-like object is required, not '{}'",
obj_cls.name
)))
}
+8 -6
View File
@@ -54,6 +54,7 @@ pub(crate) type CmpFunc = fn(
&VirtualMachine,
) -> PyResult<Either<PyObjectRef, PyComparisonValue>>;
pub(crate) type GetattroFunc = fn(PyObjectRef, PyStrRef, &VirtualMachine) -> PyResult;
pub(crate) type BufferFunc = fn(&PyObjectRef, &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
#[derive(Default)]
pub struct PyTypeSlots {
@@ -69,8 +70,6 @@ pub struct PyTypeSlots {
pub buffer: Option<BufferFunc>,
}
type BufferFunc = fn(PyObjectRef, &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
impl PyTypeSlots {
pub fn from_flags(flags: PyTpFlags) -> Self {
Self {
@@ -409,10 +408,13 @@ pub trait SlotGetattro: PyValue {
#[pyimpl]
pub trait BufferProtocol: PyValue {
#[pyslot]
fn tp_buffer(zelf: PyObjectRef, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
let zelf = PyRef::try_from_object(vm, zelf)?;
Self::get_buffer(zelf, vm)
fn tp_buffer(zelf: &PyObjectRef, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
if let Some(zelf) = zelf.downcast_ref() {
Self::get_buffer(zelf, vm)
} else {
Err(vm.new_type_error("unexpected payload for get_buffer".to_owned()))
}
}
fn get_buffer(zelf: PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
fn get_buffer(zelf: &PyRef<Self>, vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>>;
}
+2 -2
View File
@@ -868,9 +868,9 @@ impl Comparable for PyArray {
}
impl BufferProtocol for PyArray {
fn get_buffer(zelf: PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
fn get_buffer(zelf: &PyRef<Self>, _vm: &VirtualMachine) -> PyResult<Box<dyn Buffer>> {
zelf.exports.fetch_add(1);
Ok(Box::new(zelf))
Ok(Box::new(zelf.clone()))
}
}
+4 -13
View File
@@ -1402,6 +1402,7 @@ mod _io {
#[cfg(any(not(target_arch = "wasm32"), target_os = "wasi"))]
mod fileio {
use super::_io::*;
use crate::byteslike::{PyBytesLike, PyRwBytesLike};
use crate::exceptions::IntoPyException;
use crate::function::{OptionalArg, PyFuncArgs};
use crate::obj::objstr::PyStrRef;
@@ -1411,7 +1412,6 @@ mod fileio {
};
use crate::stdlib::os;
use crate::vm::VirtualMachine;
use crate::{byteslike::PyBytesLike, obj::objmemory::try_buffer_from_object};
use crossbeam_utils::atomic::AtomicCell;
use std::io::{Read, Seek, SeekFrom, Write};
@@ -1567,23 +1567,14 @@ mod fileio {
}
#[pymethod]
fn readinto(&self, obj: PyObjectRef, vm: &VirtualMachine) -> PyResult<usize> {
let buffer = try_buffer_from_object(obj, vm).map_err(|_| {
vm.new_type_error(
"readinto() argument must be read-write bytes-like object".to_owned(),
)
})?;
let mut writable = buffer
.as_contiguous_mut()
.ok_or_else(|| vm.new_value_error("buffer is not contiguous".to_owned()))?;
let length = writable.len() as u64;
fn readinto(&self, obj: PyRwBytesLike, vm: &VirtualMachine) -> PyResult<usize> {
let length = obj.len() as u64;
let handle = self.get_file(vm)?;
let mut f = handle.take(length);
let ret = f
.read(&mut *writable)
.read(&mut *obj.borrow_value())
.map_err(|_| vm.new_value_error("Error reading from Take".to_owned()))?;
self.set_file(f.into_inner())?;
+7 -11
View File
@@ -3,9 +3,10 @@ pub(crate) use decl::make_module;
#[pymodule(name = "marshal")]
mod decl {
use crate::bytecode;
use crate::obj::objbytes::{PyBytes, PyBytesRef};
use crate::byteslike::PyBytesLike;
use crate::common::borrow::BorrowValue;
use crate::obj::objbytes::PyBytes;
use crate::obj::objcode::{PyCode, PyCodeRef};
use crate::obj::objmemory::try_buffer_from_object;
use crate::pyobject::{IntoPyObject, PyObjectRef, PyResult, TryFromObject};
use crate::vm::VirtualMachine;
@@ -21,12 +22,8 @@ mod decl {
}
#[pyfunction]
fn loads(code_bytes: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyCode> {
let buffer = try_buffer_from_object(code_bytes, vm)?;
let bytes = buffer
.as_contiguous()
.ok_or_else(|| vm.new_value_error("buffer is not contiguous".to_owned()))?;
let code = bytecode::CodeObject::from_bytes(&*bytes)
fn loads(code_bytes: PyBytesLike, vm: &VirtualMachine) -> PyResult<PyCode> {
let code = bytecode::CodeObject::from_bytes(&*code_bytes.borrow_value())
.map_err(|_| vm.new_value_error("Couldn't deserialize python bytecode".to_owned()))?;
Ok(PyCode { code })
}
@@ -34,8 +31,7 @@ mod decl {
#[pyfunction]
fn load(f: PyObjectRef, vm: &VirtualMachine) -> PyResult<PyCode> {
let read_res = vm.call_method(&f, "read", vec![])?;
// FIXME:
let bytes = PyBytesRef::try_from_object(vm, read_res)?;
loads(bytes.into_object(), vm)
let bytes = PyBytesLike::try_from_object(vm, read_res)?;
loads(bytes, vm)
}
}