From e7fb11621079b5f559c0673c9b8cf488bb214ff3 Mon Sep 17 00:00:00 2001
From: Joey Hain <jmhain@protonmail.com>
Date: Thu, 28 Feb 2019 15:52:26 -0800
Subject: [PATCH 1/2] Convert more objects to `Any` payload

---
 vm/src/obj/objbool.rs  |  5 +++-
 vm/src/obj/objfloat.rs | 34 ++++++++++++++++++-----
 vm/src/obj/objiter.rs  | 62 +++++++++++++++++++++---------------------
 vm/src/obj/objrange.rs | 42 ++++++++++++++++------------
 vm/src/pyobject.rs     | 17 +++++-------
 5 files changed, 94 insertions(+), 66 deletions(-)

diff --git a/vm/src/obj/objbool.rs b/vm/src/obj/objbool.rs
index 3e0798ef50..84b048e3ae 100644
--- a/vm/src/obj/objbool.rs
+++ b/vm/src/obj/objbool.rs
@@ -1,3 +1,4 @@
+use super::objfloat::PyFloat;
 use super::objstr::PyString;
 use super::objtype;
 use crate::pyobject::{
@@ -16,9 +17,11 @@ pub fn boolval(vm: &mut VirtualMachine, obj: PyObjectRef) -> Result<bool, PyObje
     if let Some(s) = obj.payload::<PyString>() {
         return Ok(!s.value.is_empty());
     }
+    if let Some(value) = obj.payload::<PyFloat>() {
+        return Ok(*value != PyFloat::from(0.0));
+    }
     let result = match obj.payload {
         PyObjectPayload::Integer { ref value } => !value.is_zero(),
-        PyObjectPayload::Float { value } => value != 0.0,
         PyObjectPayload::Sequence { ref elements } => !elements.borrow().is_empty(),
         PyObjectPayload::Dict { ref elements } => !elements.borrow().is_empty(),
         PyObjectPayload::None { .. } => false,
diff --git a/vm/src/obj/objfloat.rs b/vm/src/obj/objfloat.rs
index b59e893e3e..a2038bffbc 100644
--- a/vm/src/obj/objfloat.rs
+++ b/vm/src/obj/objfloat.rs
@@ -3,12 +3,30 @@ use super::objint;
 use super::objstr;
 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_bigint::ToBigInt;
 use num_traits::ToPrimitive;
 
+#[derive(Debug, Copy, Clone, PartialEq)]
+pub struct PyFloat {
+    value: f64,
+}
+
+impl PyObjectPayload2 for PyFloat {
+    fn required_type(ctx: &PyContext) -> PyObjectRef {
+        ctx.float_type()
+    }
+}
+
+impl From<f64> for PyFloat {
+    fn from(value: f64) -> Self {
+        PyFloat { value }
+    }
+}
+
 fn float_repr(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
     arg_check!(vm, args, required = [(float, Some(vm.ctx.float_type()))]);
     let v = get_value(float);
@@ -50,16 +68,18 @@ fn float_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
         let type_name = objtype::get_type_name(&arg.typ());
         return Err(vm.new_type_error(format!("can't convert {} to float", type_name)));
     };
-    Ok(PyObject::new(PyObjectPayload::Float { value }, cls.clone()))
+
+    Ok(PyObject::new(
+        PyObjectPayload::AnyRustValue {
+            value: Box::new(PyFloat { value }),
+        },
+        cls.clone(),
+    ))
 }
 
 // Retrieve inner float value:
 pub fn get_value(obj: &PyObjectRef) -> f64 {
-    if let PyObjectPayload::Float { value } = &obj.payload {
-        *value
-    } else {
-        panic!("Inner error getting float: {}", obj);
-    }
+    obj.payload::<PyFloat>().unwrap().value
 }
 
 pub fn make_float(vm: &mut VirtualMachine, obj: &PyObjectRef) -> PyResult<f64> {
diff --git a/vm/src/obj/objiter.rs b/vm/src/obj/objiter.rs
index 2010da906d..9985553fb1 100644
--- a/vm/src/obj/objiter.rs
+++ b/vm/src/obj/objiter.rs
@@ -2,13 +2,14 @@
  * Various types to support iteration.
  */
 
-use super::objbool;
 use crate::pyobject::{
     PyContext, PyFuncArgs, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol,
 };
 use crate::vm::VirtualMachine;
-// use super::objstr;
-use super::objtype; // Required for arg_check! to use isinstance
+
+use super::objbool;
+use super::objrange::PyRange;
+use super::objtype;
 
 /*
  * This helper function is called at multiple places. First, it is called
@@ -129,38 +130,37 @@ fn iter_next(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
         iterated_obj: ref iterated_obj_ref,
     } = iter.payload
     {
-        match iterated_obj_ref.payload {
-            PyObjectPayload::Sequence { ref elements } => {
-                if position.get() < elements.borrow().len() {
-                    let obj_ref = elements.borrow()[position.get()].clone();
-                    position.set(position.get() + 1);
-                    Ok(obj_ref)
-                } else {
-                    Err(new_stop_iteration(vm))
-                }
+        if let Some(range) = iterated_obj_ref.payload::<PyRange>() {
+            if let Some(int) = range.get(position.get()) {
+                position.set(position.get() + 1);
+                Ok(vm.ctx.new_int(int))
+            } else {
+                Err(new_stop_iteration(vm))
             }
-
-            PyObjectPayload::Range { ref range } => {
-                if let Some(int) = range.get(position.get()) {
-                    position.set(position.get() + 1);
-                    Ok(vm.ctx.new_int(int))
-                } else {
-                    Err(new_stop_iteration(vm))
+        } else {
+            match iterated_obj_ref.payload {
+                PyObjectPayload::Sequence { ref elements } => {
+                    if position.get() < elements.borrow().len() {
+                        let obj_ref = elements.borrow()[position.get()].clone();
+                        position.set(position.get() + 1);
+                        Ok(obj_ref)
+                    } else {
+                        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))
+                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");
+                _ => {
+                    panic!("NOT IMPL");
+                }
             }
         }
     } else {
diff --git a/vm/src/obj/objrange.rs b/vm/src/obj/objrange.rs
index daa5aab52f..41a4c69645 100644
--- a/vm/src/obj/objrange.rs
+++ b/vm/src/obj/objrange.rs
@@ -4,7 +4,8 @@ use std::ops::Mul;
 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_bigint::{BigInt, Sign};
@@ -12,7 +13,7 @@ use num_integer::Integer;
 use num_traits::{One, Signed, ToPrimitive, Zero};
 
 #[derive(Debug, Clone)]
-pub struct RangeType {
+pub struct PyRange {
     // Unfortunately Rust's built in range type doesn't support things like indexing
     // or ranges where start > end so we need to roll our own.
     pub start: BigInt,
@@ -20,7 +21,13 @@ pub struct RangeType {
     pub step: BigInt,
 }
 
-impl RangeType {
+impl PyObjectPayload2 for PyRange {
+    fn required_type(ctx: &PyContext) -> PyObjectRef {
+        ctx.range_type()
+    }
+}
+
+impl PyRange {
     #[inline]
     pub fn try_len(&self) -> Option<usize> {
         match self.step.sign() {
@@ -116,12 +123,12 @@ impl RangeType {
         };
 
         match self.step.sign() {
-            Sign::Plus => RangeType {
+            Sign::Plus => PyRange {
                 start,
                 end: &self.start - 1,
                 step: -&self.step,
             },
-            Sign::Minus => RangeType {
+            Sign::Minus => PyRange {
                 start,
                 end: &self.start + 1,
                 step: -&self.step,
@@ -139,12 +146,8 @@ impl RangeType {
     }
 }
 
-pub fn get_value(obj: &PyObjectRef) -> RangeType {
-    if let PyObjectPayload::Range { range } = &obj.payload {
-        range.clone()
-    } else {
-        panic!("Inner error getting range {:?}", obj);
-    }
+pub fn get_value(obj: &PyObjectRef) -> PyRange {
+    obj.payload::<PyRange>().unwrap().clone()
 }
 
 pub fn init(context: &PyContext) {
@@ -223,8 +226,8 @@ fn range_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
         Err(vm.new_value_error("range with 0 step size".to_string()))
     } else {
         Ok(PyObject::new(
-            PyObjectPayload::Range {
-                range: RangeType { start, end, step },
+            PyObjectPayload::AnyRustValue {
+                value: Box::new(PyRange { start, end, step }),
             },
             cls.clone(),
         ))
@@ -251,7 +254,12 @@ fn range_reversed(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
     Ok(PyObject::new(
         PyObjectPayload::Iterator {
             position: Cell::new(0),
-            iterated_obj: PyObject::new(PyObjectPayload::Range { range }, vm.ctx.range_type()),
+            iterated_obj: PyObject::new(
+                PyObjectPayload::AnyRustValue {
+                    value: Box::new(range),
+                },
+                vm.ctx.range_type(),
+            ),
         },
         vm.ctx.iter_type(),
     ))
@@ -316,12 +324,12 @@ fn range_getitem(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
             };
 
             Ok(PyObject::new(
-                PyObjectPayload::Range {
-                    range: RangeType {
+                PyObjectPayload::AnyRustValue {
+                    value: Box::new(PyRange {
                         start: new_start,
                         end: new_end,
                         step: new_step,
-                    },
+                    }),
                 },
                 vm.ctx.range_type(),
             ))
diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs
index c39aa71ae6..bfb33871e8 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -459,8 +459,13 @@ impl PyContext {
         )
     }
 
-    pub fn new_float(&self, i: f64) -> PyObjectRef {
-        PyObject::new(PyObjectPayload::Float { value: i }, self.float_type())
+    pub fn new_float(&self, value: f64) -> PyObjectRef {
+        PyObject::new(
+            PyObjectPayload::AnyRustValue {
+                value: Box::new(objfloat::PyFloat::from(value)),
+            },
+            self.float_type(),
+        )
     }
 
     pub fn new_complex(&self, i: Complex64) -> PyObjectRef {
@@ -1245,9 +1250,6 @@ pub enum PyObjectPayload {
     Integer {
         value: BigInt,
     },
-    Float {
-        value: f64,
-    },
     Complex {
         value: Complex64,
     },
@@ -1284,9 +1286,6 @@ pub enum PyObjectPayload {
         stop: Option<BigInt>,
         step: Option<BigInt>,
     },
-    Range {
-        range: objrange::RangeType,
-    },
     MemoryView {
         obj: PyObjectRef,
     },
@@ -1340,7 +1339,6 @@ impl fmt::Debug for PyObjectPayload {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self {
             PyObjectPayload::Integer { ref value } => write!(f, "int {}", value),
-            PyObjectPayload::Float { ref value } => write!(f, "float {}", 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),
@@ -1348,7 +1346,6 @@ impl fmt::Debug for PyObjectPayload {
             PyObjectPayload::Dict { .. } => write!(f, "dict"),
             PyObjectPayload::Set { .. } => write!(f, "set"),
             PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),
-            PyObjectPayload::Range { .. } => write!(f, "range"),
             PyObjectPayload::Iterator { .. } => write!(f, "iterator"),
             PyObjectPayload::EnumerateIterator { .. } => write!(f, "enumerate"),
             PyObjectPayload::FilterIterator { .. } => write!(f, "filter"),

From 2d71f6de288cd8dce359f16499c2df56e0f03bb5 Mon Sep 17 00:00:00 2001
From: Joey Hain <jmhain@protonmail.com>
Date: Sun, 3 Mar 2019 20:01:07 -0800
Subject: [PATCH 2/2] 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 0cabf23fdc..7e03d34d3d 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<Vec<u8>>,
+}
+
+impl PyByteArray {
+    pub fn new(data: Vec<u8>) -> 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<Target = Vec<u8>> + 'a {
+    obj.payload::<PyByteArray>().unwrap().value.borrow()
+}
+
+pub fn get_mut_value<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Vec<u8>> + 'a {
+    obj.payload::<PyByteArray>().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 6ab2f72af2..d285b86e9a 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<u8>,
+}
+
+impl PyBytes {
+    pub fn new(data: Vec<u8>) -> 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<Target = Vec<u8>> + '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<Target = Vec<u8>> + 'a {
-    if let PyObjectPayload::Bytes { ref value } = obj.payload {
-        value.borrow_mut()
-    } else {
-        panic!("Inner error getting bytearray {:?}", obj);
-    }
+    &obj.payload::<PyBytes>().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 9985553fb1..049ea8be39 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::<PyBytes>() {
+            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::<PyByteArray>() {
+            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 bfb33871e8..038eb1d0f8 100644
--- a/vm/src/pyobject.rs
+++ b/vm/src/pyobject.rs
@@ -483,8 +483,8 @@ impl PyContext {
 
     pub fn new_bytes(&self, data: Vec<u8>) -> 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<u8>) -> 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<Vec<u8>>,
-    },
     Sequence {
         elements: RefCell<Vec<PyObjectRef>>,
     },
@@ -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 077f907d89..95f6a10a9e 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::<PyByteArray>() {
+            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::<PyByteArray>() {
         //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::<PyByteArray>() {
+        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())),
     }
 }