diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 7bbaad581..e38d698d2 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -499,8 +499,6 @@ fn builtin_max(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(x) } -// builtin_memoryview - fn builtin_min(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let candidates = if args.args.len() > 1 { args.args.clone() @@ -774,6 +772,7 @@ pub fn make_module(ctx: &PyContext) -> PyObjectRef { ctx.set_attr(&py_mod, "locals", ctx.new_rustfunc(builtin_locals)); ctx.set_attr(&py_mod, "map", ctx.new_rustfunc(builtin_map)); ctx.set_attr(&py_mod, "max", ctx.new_rustfunc(builtin_max)); + ctx.set_attr(&py_mod, "memoryview", ctx.memoryview_type()); ctx.set_attr(&py_mod, "min", ctx.new_rustfunc(builtin_min)); ctx.set_attr(&py_mod, "object", ctx.object()); ctx.set_attr(&py_mod, "oct", ctx.new_rustfunc(builtin_oct)); diff --git a/vm/src/obj/mod.rs b/vm/src/obj/mod.rs index 96cebc802..16670fa5d 100644 --- a/vm/src/obj/mod.rs +++ b/vm/src/obj/mod.rs @@ -13,6 +13,7 @@ pub mod objgenerator; pub mod objint; pub mod objiter; pub mod objlist; +pub mod objmemory; pub mod objobject; pub mod objproperty; pub mod objsequence; diff --git a/vm/src/obj/objmemory.rs b/vm/src/obj/objmemory.rs new file mode 100644 index 000000000..2398eed8d --- /dev/null +++ b/vm/src/obj/objmemory.rs @@ -0,0 +1,27 @@ + +use super::objtype; + +use super::super::pyobject::{ + PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, PyResult, TypeProtocol +}; +use super::super::vm::VirtualMachine; + + +pub fn new_memory_view(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(cls, None), (bytes_object, None)] + ); + vm.ctx.set_attr(&cls, "obj", bytes_object.clone()); + Ok(PyObject::new( + PyObjectKind::MemoryView { obj: bytes_object.clone() }, + cls.clone() + )) + +} + +pub fn init(ctx: &PyContext) { + let ref memoryview_type = ctx.memoryview_type; + ctx.set_attr(&memoryview_type, "__new__", ctx.new_rustfunc(new_memory_view)); +} diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index 35b93fa69..62e8c6b23 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -14,6 +14,7 @@ use super::obj::objgenerator; use super::obj::objint; use super::obj::objiter; use super::obj::objlist; +use super::obj::objmemory; use super::obj::objobject; use super::obj::objproperty; use super::obj::objset; @@ -114,6 +115,7 @@ pub struct PyContext { pub true_value: PyObjectRef, pub false_value: PyObjectRef, pub list_type: PyObjectRef, + pub memoryview_type: PyObjectRef, pub none: PyObjectRef, pub tuple_type: PyObjectRef, pub set_type: PyObjectRef, @@ -197,6 +199,7 @@ impl PyContext { let tuple_type = create_type("tuple", &type_type, &object_type, &dict_type); let iter_type = create_type("iter", &type_type, &object_type, &dict_type); let bool_type = create_type("bool", &type_type, &int_type, &dict_type); + let memoryview_type = create_type("memoryview", &type_type, &object_type, &dict_type); let code_type = create_type("code", &type_type, &int_type, &dict_type); let exceptions = exceptions::ExceptionZoo::new(&type_type, &object_type, &dict_type); @@ -217,6 +220,7 @@ impl PyContext { ); let context = PyContext { bool_type: bool_type, + memoryview_type : memoryview_type, bytearray_type: bytearray_type, bytes_type: bytes_type, code_type: code_type, @@ -261,6 +265,7 @@ impl PyContext { objbytes::init(&context); objbytearray::init(&context); objproperty::init(&context); + objmemory::init(&context); objstr::init(&context); objsuper::init(&context); objtuple::init(&context); @@ -320,6 +325,10 @@ impl PyContext { self.bool_type.clone() } + pub fn memoryview_type(&self) -> PyObjectRef { + self.memoryview_type.clone() + } + pub fn tuple_type(&self) -> PyObjectRef { self.tuple_type.clone() } @@ -831,6 +840,9 @@ pub enum PyObjectKind { stop: Option, step: Option, }, + MemoryView { + obj : PyObjectRef + }, Code { code: bytecode::CodeObject, }, @@ -881,6 +893,7 @@ impl fmt::Debug for PyObjectKind { &PyObjectKind::Float { ref value } => write!(f, "float {}", value), &PyObjectKind::Complex { ref value } => write!(f, "complex {}", value), &PyObjectKind::Bytes { ref value } => write!(f, "bytes/bytearray {:?}", value), + &PyObjectKind::MemoryView { ref obj } => write!(f, "bytes/bytearray {:?}", obj), &PyObjectKind::Sequence { elements: _ } => write!(f, "list or tuple"), &PyObjectKind::Dict { elements: _ } => write!(f, "dict"), &PyObjectKind::Set { elements: _ } => write!(f, "set"), @@ -934,6 +947,7 @@ impl PyObject { PyObjectKind::Float { ref value } => format!("{:?}", value), PyObjectKind::Complex { ref value } => format!("{:?}", value), PyObjectKind::Bytes { ref value } => format!("b'{:?}'", value), + PyObjectKind::MemoryView { ref obj } => format!("b'{:?}'", obj), PyObjectKind::Sequence { ref elements } => format!( "(/[{}]/)", elements diff --git a/vm/src/stdlib/io.rs b/vm/src/stdlib/io.rs index 15b116795..df22a52d1 100644 --- a/vm/src/stdlib/io.rs +++ b/vm/src/stdlib/io.rs @@ -2,9 +2,21 @@ * I/O core tools. */ -// use super::super::obj::{objstr, objtype}; -use super::super::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult}; -use super::super::VirtualMachine; + +use std::fs::File; +use std::io::prelude::*; +use std::io::{BufReader,BufWriter}; + +use super::super::obj::objstr::get_value; + +use super::super::obj::objtype; + +use super::super::pyobject::{ + PyContext, PyFuncArgs, PyObjectKind, PyObjectRef, PyResult, TypeProtocol, AttributeProtocol +}; + +use super::super::vm::VirtualMachine; + fn string_io_init(vm: &mut VirtualMachine, _args: PyFuncArgs) -> PyResult { // arg_check!(vm, args, required = [(s, Some(vm.ctx.str_type()))]); @@ -29,21 +41,158 @@ fn bytes_io_getvalue(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Ok(vm.get_none()) } +fn buffered_io_base_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + // arg_check!(vm, args); + + // TODO + Ok(vm.get_none()) +} + +fn file_io_init(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(file_io, None), (name, Some(vm.ctx.str_type()))] + ); + + vm.ctx.set_attr(&file_io, "name", name.clone()); + Ok(vm.get_none()) +} + +fn file_io_read(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(file_io, None)] + ); + let py_name = file_io.get_attr("name").unwrap(); + let f = match File::open(get_value(& py_name)) { + Ok(v) => Ok(v), + Err(v) => Err(vm.new_type_error("Error opening file".to_string())), + }; + + let buffer = match f { + Ok(v) => Ok(BufReader::new(v)), + Err(v) => Err(vm.new_type_error("Error reading from file".to_string())) + }; + + let mut bytes = vec![]; + if let Ok(mut buff) = buffer { + buff.read_to_end(&mut bytes); + } + + Ok(vm.ctx.new_bytes(bytes)) +} + + +fn file_io_read_into(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(file_io, None), (view, Some(vm.ctx.bytes_type()))] + ); + let py_name = file_io.get_attr("name").unwrap(); + let f = match File::open(get_value(& py_name)) { + Ok(v) => Ok(v), + Err(v) => Err(vm.new_type_error("Error opening file".to_string())), + }; + + let buffer = match f { + Ok(v) => Ok(BufReader::new(v)), + Err(v) => Err(vm.new_type_error("Error reading from file".to_string())) + }; + + + match view.borrow_mut().kind { + PyObjectKind::Bytes { ref mut value } => { + if let Ok(mut buff) = buffer { + buff.read_to_end(&mut *value); + }; + }, + _ => {} + }; + + Ok(vm.get_none()) +} + +fn buffered_reader_read(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!(vm, args); + // TODO + Ok(vm.get_none()) +} + +fn io_open(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { + arg_check!( + vm, + args, + required = [(file, None), (mode, None)] + ); + + + Ok(vm.get_none()) + //mode is optional: 'rt' is the default mode (open from reading text) + //To start we construct a FileIO (subclass of RawIOBase) + //This is subsequently consumed by a Buffered_class of type depending + //operation in the mode. i.e: + // updating => PyBufferedRandom + // creating || writing || appending => BufferedWriter + // reading => BufferedReader + // If the mode is binary this Buffered class is returned directly at + // this point. + + //If the mode is text this buffer type is consumed on construction of + //a TextIOWrapper which is subsequently returned. +} + + pub fn mk_module(ctx: &PyContext) -> PyObjectRef { let py_mod = ctx.new_module(&"io".to_string(), ctx.new_scope(None)); - + ctx.set_attr(&py_mod, "open", ctx.new_rustfunc(io_open)); + //IOBase the abstract base class of the IO Module let io_base = ctx.new_class("IOBase", ctx.object()); ctx.set_attr(&py_mod, "IOBase", io_base.clone()); + // IOBase Subclasses + let raw_io_base = ctx.new_class("RawIOBase", ctx.object()); + ctx.set_attr(&py_mod, "RawIOBase", raw_io_base.clone()); + + let buffered_io_base = ctx.new_class("BufferedIOBase", io_base.clone()); + ctx.set_attr(&buffered_io_base, "__init__", ctx.new_rustfunc(buffered_io_base_init)); + ctx.set_attr(&py_mod, "BufferedIOBase", buffered_io_base.clone()); + + let text_io_base = ctx.new_class("TextIOBase", io_base.clone()); + ctx.set_attr(&py_mod, "TextIOBase", text_io_base.clone()); + + // RawBaseIO Subclasses + let file_io = ctx.new_class("FileIO", raw_io_base.clone()); + ctx.set_attr(&file_io, "__init__", ctx.new_rustfunc(file_io_init)); + ctx.set_attr(&file_io, "name", ctx.str_type()); + ctx.set_attr(&file_io, "read", ctx.new_rustfunc(file_io_read)); + ctx.set_attr(&file_io, "read_into", ctx.new_rustfunc(file_io_read_into)); + ctx.set_attr(&py_mod, "FileIO", file_io.clone()); + + // BufferedIOBase Subclasses + let buffered_reader = ctx.new_class("BufferedReader", buffered_io_base.clone()); + ctx.set_attr(&py_mod, "BufferedReader", buffered_reader.clone()); + + let buffered_reader = ctx.new_class("BufferedWriter", buffered_io_base.clone()); + ctx.set_attr(&py_mod, "BufferedWriter", buffered_reader.clone()); + + //TextIOBase Subclass + let text_io_wrapper = ctx.new_class("TextIOWrapper", ctx.object()); + ctx.set_attr(&py_mod, "TextIOWrapper", text_io_wrapper.clone()); + + // BytesIO: in-memory bytes let string_io = ctx.new_class("StringIO", io_base.clone()); ctx.set_attr(&string_io, "__init__", ctx.new_rustfunc(string_io_init)); ctx.set_attr(&string_io, "getvalue", ctx.new_rustfunc(string_io_getvalue)); ctx.set_attr(&py_mod, "StringIO", string_io); + // StringIO: in-memory text let bytes_io = ctx.new_class("BytesIO", io_base.clone()); ctx.set_attr(&bytes_io, "__init__", ctx.new_rustfunc(bytes_io_init)); ctx.set_attr(&bytes_io, "getvalue", ctx.new_rustfunc(bytes_io_getvalue)); ctx.set_attr(&py_mod, "BytesIO", bytes_io); py_mod -} +} \ No newline at end of file