Skip to content

Add PyObjectPayload trait and use it for PyObject.payload #670

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Mar 15, 2019
31 changes: 19 additions & 12 deletions vm/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,19 @@ impl<'a, T> Iterator for Iter<'a, T> {
}
}

#[derive(Debug, Clone)]
#[derive(Clone)]
pub struct Scope {
locals: RcList<PyObjectRef>,
pub globals: PyObjectRef,
}

impl fmt::Debug for Scope {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: have a more informative Debug impl that DOESN'T recurse and cause a stack overflow
f.write_str("Scope")
}
}

impl Scope {
pub fn new(locals: Option<PyObjectRef>, globals: PyObjectRef) -> Scope {
let locals = match locals {
Expand All @@ -99,10 +106,7 @@ impl Scope {
}

pub fn get_only_locals(&self) -> Option<PyObjectRef> {
match self.locals.iter().next() {
Some(dict) => Some(dict.clone()),
None => None,
}
self.locals.iter().next().cloned()
}

pub fn child_scope_with_locals(&self, locals: PyObjectRef) -> Scope {
Expand Down Expand Up @@ -1211,22 +1215,25 @@ impl fmt::Debug for Frame {
.stack
.borrow()
.iter()
.map(|elem| format!("\n > {:?}", elem))
.collect::<Vec<_>>()
.join("");
.map(|elem| {
if elem.payload.as_any().is::<Frame>() {
"\n > {frame}".to_string()
} else {
format!("\n > {:?}", elem)
}
})
.collect::<String>();
let block_str = self
.blocks
.borrow()
.iter()
.map(|elem| format!("\n > {:?}", elem))
.collect::<Vec<_>>()
.join("");
.collect::<String>();
let local_str = match self.scope.get_locals().payload::<PyDict>() {
Some(dict) => objdict::get_key_value_pairs_from_content(&dict.entries.borrow())
.iter()
.map(|elem| format!("\n {:?} = {:?}", elem.0, elem.1))
.collect::<Vec<_>>()
.join(""),
.collect::<String>(),
None => panic!("locals unexpectedly not wrapping a dict!",),
};
write!(
Expand Down
10 changes: 9 additions & 1 deletion vm/src/obj/objdict.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::cell::{Cell, RefCell};
use std::collections::HashMap;
use std::fmt;
use std::ops::{Deref, DerefMut};

use crate::pyobject::{
Expand All @@ -14,13 +15,20 @@ use super::objtype;

pub type DictContentType = HashMap<String, (PyObjectRef, PyObjectRef)>;

#[derive(Default, Debug)]
#[derive(Default)]
pub struct PyDict {
// TODO: should be private
pub entries: RefCell<DictContentType>,
}
pub type PyDictRef = PyRef<PyDict>;

impl fmt::Debug for PyDict {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: implement more detailed, non-recursive Debug formatter
f.write_str("dict")
}
}

impl PyValue for PyDict {
fn required_type(ctx: &PyContext) -> PyObjectRef {
ctx.dict_type()
Expand Down
10 changes: 9 additions & 1 deletion vm/src/obj/objlist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,21 @@ use crate::pyobject::{
};
use crate::vm::{ReprGuard, VirtualMachine};
use num_traits::ToPrimitive;
use std::fmt;

#[derive(Debug, Default)]
#[derive(Default)]
pub struct PyList {
// TODO: shouldn't be public
pub elements: RefCell<Vec<PyObjectRef>>,
}

impl fmt::Debug for PyList {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: implement more detailed, non-recursive Debug formatter
f.write_str("list")
}
}

impl From<Vec<PyObjectRef>> for PyList {
fn from(elements: Vec<PyObjectRef>) -> Self {
PyList {
Expand Down
8 changes: 7 additions & 1 deletion vm/src/obj/objobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,19 @@ use super::objtype;
use crate::obj::objproperty::PropertyBuilder;
use crate::pyobject::{
AttributeProtocol, DictProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObjectRef,
PyRef, PyResult, TypeProtocol,
PyRef, PyResult, PyValue, TypeProtocol,
};
use crate::vm::VirtualMachine;

#[derive(Clone, Debug)]
pub struct PyInstance;

impl PyValue for PyInstance {
fn required_type(ctx: &PyContext) -> PyObjectRef {
ctx.object()
}
}

pub type PyInstanceRef = PyRef<PyInstance>;

pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {
Expand Down
13 changes: 10 additions & 3 deletions vm/src/obj/objset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
*/

use std::cell::{Cell, RefCell};
use std::collections::hash_map::DefaultHasher;
use std::collections::HashMap;
use std::collections::{hash_map::DefaultHasher, HashMap};
use std::fmt;
use std::hash::{Hash, Hasher};

use super::objbool;
Expand All @@ -17,11 +17,18 @@ use crate::pyobject::{
};
use crate::vm::{ReprGuard, VirtualMachine};

#[derive(Debug, Default)]
#[derive(Default)]
pub struct PySet {
elements: RefCell<HashMap<u64, PyObjectRef>>,
}

impl fmt::Debug for PySet {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: implement more detailed, non-recursive Debug formatter
f.write_str("set")
}
}

impl PyValue for PySet {
fn required_type(ctx: &PyContext) -> PyObjectRef {
ctx.set_type()
Expand Down
10 changes: 9 additions & 1 deletion vm/src/obj/objtuple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::cell::{Cell, RefCell};
use std::fmt;
use std::hash::{Hash, Hasher};

use crate::pyobject::{
Expand All @@ -15,13 +16,20 @@ use super::objsequence::{
use super::objstr;
use super::objtype;

#[derive(Debug, Default)]
#[derive(Default)]
pub struct PyTuple {
// TODO: shouldn't be public
// TODO: tuples are immutable, remove this RefCell
pub elements: RefCell<Vec<PyObjectRef>>,
}

impl fmt::Debug for PyTuple {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// TODO: implement more informational, non-recursive Debug formatter
f.write_str("tuple")
}
}

impl From<Vec<PyObjectRef>> for PyTuple {
fn from(elements: Vec<PyObjectRef>) -> Self {
PyTuple {
Expand Down
28 changes: 17 additions & 11 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -623,11 +623,7 @@ impl PyContext {
}

pub fn new_instance(&self, class: PyObjectRef, dict: Option<PyAttributes>) -> PyObjectRef {
let dict = if let Some(dict) = dict {
dict
} else {
PyAttributes::new()
};
let dict = dict.unwrap_or_default();
PyObject {
typ: class,
dict: Some(RefCell::new(dict)),
Expand Down Expand Up @@ -697,7 +693,7 @@ impl Default for PyContext {
pub struct PyObject {
pub typ: PyObjectRef,
pub dict: Option<RefCell<PyAttributes>>, // __dict__ member
pub payload: Box<dyn Any>,
pub payload: Box<dyn PyObjectPayload>,
}

/// A reference to a Python object.
Expand Down Expand Up @@ -1557,7 +1553,7 @@ impl PyValue for PyIteratorValue {
}

impl PyObject {
pub fn new<T: PyValue>(payload: T, typ: PyObjectRef) -> PyObjectRef {
pub fn new<T: PyObjectPayload>(payload: T, typ: PyObjectRef) -> PyObjectRef {
PyObject {
typ,
dict: Some(RefCell::new(PyAttributes::new())),
Expand All @@ -1571,14 +1567,13 @@ impl PyObject {
Rc::new(self)
}

#[inline]
pub fn payload<T: PyValue>(&self) -> Option<&T> {
self.payload.downcast_ref()
self.payload.as_any().downcast_ref()
}
}

// The intention is for this to replace `PyObjectPayload` once everything is
// converted to use `PyObjectPayload::AnyRustvalue`.
pub trait PyValue: Any + fmt::Debug + Sized {
pub trait PyValue: fmt::Debug + Sized + 'static {
fn required_type(ctx: &PyContext) -> PyObjectRef;

fn into_ref(self, ctx: &PyContext) -> PyRef<Self> {
Expand All @@ -1603,6 +1598,17 @@ pub trait PyValue: Any + fmt::Debug + Sized {
}
}

pub trait PyObjectPayload: Any + fmt::Debug + 'static {
fn as_any(&self) -> &dyn Any;
}

impl<T: PyValue + 'static> PyObjectPayload for T {
#[inline]
fn as_any(&self) -> &dyn Any {
self
}
}

impl FromPyObjectRef for PyRef<PyClass> {
fn from_pyobj(obj: &PyObjectRef) -> Self {
if let Some(_) = obj.payload::<PyClass>() {
Expand Down
4 changes: 2 additions & 2 deletions vm/src/stdlib/re.rs
Original file line number Diff line number Diff line change
Expand Up @@ -197,15 +197,15 @@ fn match_end(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
/// Retrieve inner rust regex from python object:
fn get_regex<'a>(obj: &'a PyObjectRef) -> &'a Regex {
// TODO: Regex shouldn't be stored in payload directly, create newtype wrapper
if let Some(regex) = obj.payload.downcast_ref::<Regex>() {
if let Some(regex) = obj.payload::<Regex>() {
return regex;
}
panic!("Inner error getting regex {:?}", obj);
}

/// Retrieve inner rust match from python object:
fn get_match<'a>(obj: &'a PyObjectRef) -> &'a PyMatch {
if let Some(value) = obj.payload.downcast_ref::<PyMatch>() {
if let Some(value) = obj.payload::<PyMatch>() {
return value;
}
panic!("Inner error getting match {:?}", obj);
Expand Down
2 changes: 1 addition & 1 deletion wasm/lib/src/browser_module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ impl PyPromise {
}

pub fn get_promise_value(obj: &PyObjectRef) -> Promise {
if let Some(promise) = obj.payload.downcast_ref::<PyPromise>() {
if let Some(promise) = obj.payload::<PyPromise>() {
return promise.value.clone();
}
panic!("Inner error getting promise")
Expand Down