From 2d71f6de288cd8dce359f16499c2df56e0f03bb5 Mon Sep 17 00:00:00 2001 From: Joey Hain Date: Sun, 3 Mar 2019 20:01:07 -0800 Subject: [PATCH] bytes and bytearray --- vm/src/obj/objbytearray.rs | 49 ++++++++++++++++++++++++++++---------- vm/src/obj/objbytes.rs | 49 ++++++++++++++++++++++++-------------- vm/src/obj/objiter.rs | 28 ++++++++++++++-------- vm/src/pyobject.rs | 12 ++++------ vm/src/stdlib/io.rs | 20 ++++++++-------- 5 files changed, 100 insertions(+), 58 deletions(-) diff --git a/vm/src/obj/objbytearray.rs b/vm/src/obj/objbytearray.rs index 0cabf23fd..7e03d34d3 100644 --- a/vm/src/obj/objbytearray.rs +++ b/vm/src/obj/objbytearray.rs @@ -1,17 +1,47 @@ //! Implementation of the python bytearray object. use std::cell::RefCell; +use std::ops::{Deref, DerefMut}; -use crate::pyobject::{PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyResult, TypeProtocol}; +use crate::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult, + TypeProtocol, +}; use super::objint; -use super::objbytes::get_mut_value; -use super::objbytes::get_value; use super::objtype; use crate::vm::VirtualMachine; use num_traits::ToPrimitive; +#[derive(Debug)] +pub struct PyByteArray { + // TODO: shouldn't be public + pub value: RefCell>, +} + +impl PyByteArray { + pub fn new(data: Vec) -> Self { + PyByteArray { + value: RefCell::new(data), + } + } +} + +impl PyObjectPayload2 for PyByteArray { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.bytearray_type() + } +} + +pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { + obj.payload::().unwrap().value.borrow() +} + +pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { + obj.payload::().unwrap().value.borrow_mut() +} + // Binary data support /// Fill bytearray class methods dictionary. @@ -143,8 +173,8 @@ fn bytearray_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { vec![] }; Ok(PyObject::new( - PyObjectPayload::Bytes { - value: RefCell::new(value), + PyObjectPayload::AnyRustValue { + value: Box::new(PyByteArray::new(value)), }, cls.clone(), )) @@ -290,13 +320,8 @@ fn bytearray_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { fn bytearray_clear(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!(vm, args, required = [(zelf, Some(vm.ctx.bytearray_type()))]); - match zelf.payload { - PyObjectPayload::Bytes { ref value } => { - value.borrow_mut().clear(); - Ok(vm.get_none()) - } - _ => panic!("Bytearray has incorrect payload."), - } + get_mut_value(zelf).clear(); + Ok(vm.get_none()) } fn bytearray_pop(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objbytes.rs b/vm/src/obj/objbytes.rs index 6ab2f72af..d285b86e9 100644 --- a/vm/src/obj/objbytes.rs +++ b/vm/src/obj/objbytes.rs @@ -1,16 +1,41 @@ -use std::cell::{Cell, RefCell}; +use std::cell::Cell; use std::hash::{Hash, Hasher}; use std::ops::Deref; -use std::ops::DerefMut; use super::objint; use super::objtype; use crate::pyobject::{ - PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectPayload2, PyObjectRef, PyResult, + TypeProtocol, }; use crate::vm::VirtualMachine; use num_traits::ToPrimitive; +#[derive(Debug)] +pub struct PyBytes { + value: Vec, +} + +impl PyBytes { + pub fn new(data: Vec) -> Self { + PyBytes { value: data } + } +} + +impl Deref for PyBytes { + type Target = [u8]; + + fn deref(&self) -> &[u8] { + &self.value + } +} + +impl PyObjectPayload2 for PyBytes { + fn required_type(ctx: &PyContext) -> PyObjectRef { + ctx.bytes_type() + } +} + // Binary data support // Fill bytes class methods: @@ -71,8 +96,8 @@ fn bytes_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { }; Ok(PyObject::new( - PyObjectPayload::Bytes { - value: RefCell::new(value), + PyObjectPayload::AnyRustValue { + value: Box::new(PyBytes::new(value)), }, cls.clone(), )) @@ -170,19 +195,7 @@ fn bytes_hash(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } pub fn get_value<'a>(obj: &'a PyObjectRef) -> impl Deref> + 'a { - if let PyObjectPayload::Bytes { ref value } = obj.payload { - value.borrow() - } else { - panic!("Inner error getting bytearray {:?}", obj); - } -} - -pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut> + 'a { - if let PyObjectPayload::Bytes { ref value } = obj.payload { - value.borrow_mut() - } else { - panic!("Inner error getting bytearray {:?}", obj); - } + &obj.payload::().unwrap().value } fn bytes_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs index 9985553fb..049ea8be3 100644 --- a/vm/src/obj/objiter.rs +++ b/vm/src/obj/objiter.rs @@ -8,6 +8,8 @@ use crate::pyobject::{ use crate::vm::VirtualMachine; use super::objbool; +use super::objbytearray::PyByteArray; +use super::objbytes::PyBytes; use super::objrange::PyRange; use super::objtype; @@ -137,6 +139,22 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { } else { Err(new_stop_iteration(vm)) } + } else if let Some(bytes) = iterated_obj_ref.payload::() { + if position.get() < bytes.len() { + let obj_ref = vm.ctx.new_int(bytes[position.get()]); + position.set(position.get() + 1); + Ok(obj_ref) + } else { + Err(new_stop_iteration(vm)) + } + } else if let Some(bytes) = iterated_obj_ref.payload::() { + if position.get() < bytes.value.borrow().len() { + let obj_ref = vm.ctx.new_int(bytes.value.borrow()[position.get()]); + position.set(position.get() + 1); + Ok(obj_ref) + } else { + Err(new_stop_iteration(vm)) + } } else { match iterated_obj_ref.payload { PyObjectPayload::Sequence { ref elements } => { @@ -148,16 +166,6 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Err(new_stop_iteration(vm)) } } - PyObjectPayload::Bytes { ref value } => { - if position.get() < value.borrow().len() { - let obj_ref = vm.ctx.new_int(value.borrow()[position.get()]); - position.set(position.get() + 1); - Ok(obj_ref) - } else { - Err(new_stop_iteration(vm)) - } - } - _ => { panic!("NOT IMPL"); } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index bfb33871e..038eb1d0f 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -483,8 +483,8 @@ impl PyContext { pub fn new_bytes(&self, data: Vec) -> PyObjectRef { PyObject::new( - PyObjectPayload::Bytes { - value: RefCell::new(data), + PyObjectPayload::AnyRustValue { + value: Box::new(objbytes::PyBytes::new(data)), }, self.bytes_type(), ) @@ -492,8 +492,8 @@ impl PyContext { pub fn new_bytearray(&self, data: Vec) -> PyObjectRef { PyObject::new( - PyObjectPayload::Bytes { - value: RefCell::new(data), + PyObjectPayload::AnyRustValue { + value: Box::new(objbytearray::PyByteArray::new(data)), }, self.bytearray_type(), ) @@ -1253,9 +1253,6 @@ pub enum PyObjectPayload { Complex { value: Complex64, }, - Bytes { - value: RefCell>, - }, Sequence { elements: RefCell>, }, @@ -1340,7 +1337,6 @@ impl fmt::Debug for PyObjectPayload { match self { PyObjectPayload::Integer { ref value } => write!(f, "int {}", value), PyObjectPayload::Complex { ref value } => write!(f, "complex {}", value), - PyObjectPayload::Bytes { ref value } => write!(f, "bytes/bytearray {:?}", value), PyObjectPayload::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj), PyObjectPayload::Sequence { .. } => write!(f, "list or tuple"), PyObjectPayload::Dict { .. } => write!(f, "dict"), diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 077f907d8..95f6a10a9 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -15,13 +15,13 @@ use num_traits::ToPrimitive; //custom imports use super::os; +use crate::obj::objbytearray::PyByteArray; use crate::obj::objbytes; use crate::obj::objint; use crate::obj::objstr; use crate::pyobject::{ - AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, - PyResult, TypeProtocol, + AttributeProtocol, BufferProtocol, PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol, }; use crate::import; @@ -86,8 +86,8 @@ fn buffered_reader_read(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { .map_err(|_| vm.new_value_error("IO Error".to_string()))?; //Copy bytes from the buffer vector into the results vector - if let PyObjectPayload::Bytes { ref value } = buffer.payload { - result.extend(value.borrow().iter().cloned()); + if let Some(bytes) = buffer.payload::() { + result.extend_from_slice(&bytes.value.borrow()); }; let len = vm.get_method(buffer.clone(), &"__len__".to_string()); @@ -169,10 +169,10 @@ fn file_io_readinto(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let handle = os::rust_file(raw_fd); let mut f = handle.take(length); - if let PyObjectPayload::Bytes { ref value } = obj.payload { + if let Some(bytes) = obj.payload::() { //TODO: Implement for MemoryView - let mut value_mut = value.borrow_mut(); + let mut value_mut = bytes.value.borrow_mut(); value_mut.clear(); match f.read_to_end(&mut value_mut) { Ok(_) => {} @@ -200,9 +200,9 @@ fn file_io_write(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { //to support windows - i.e. raw file_handles let mut handle = os::rust_file(raw_fd); - match obj.payload { - PyObjectPayload::Bytes { ref value } => { - let value_mut = value.borrow(); + match obj.payload::() { + Some(bytes) => { + let value_mut = bytes.value.borrow(); match handle.write(&value_mut[..]) { Ok(len) => { //reset raw fd on the FileIO object @@ -215,7 +215,7 @@ fn file_io_write(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Err(_) => Err(vm.new_value_error("Error Writing Bytes to Handle".to_string())), } } - _ => Err(vm.new_value_error("Expected Bytes Object".to_string())), + None => Err(vm.new_value_error("Expected Bytes Object".to_string())), } }