Skip to content

Commit a1e0c03

Browse files
authored
Merge pull request RustPython#670 from coolreader18/pyvaluepayload
Add PyObjectPayload trait and use it for PyObject.payload
2 parents 529da3f + 8c1f181 commit a1e0c03

File tree

9 files changed

+83
-33
lines changed

9 files changed

+83
-33
lines changed

vm/src/frame.rs

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,19 @@ impl<'a, T> Iterator for Iter<'a, T> {
7676
}
7777
}
7878

79-
#[derive(Debug, Clone)]
79+
#[derive(Clone)]
8080
pub struct Scope {
8181
locals: RcList<PyObjectRef>,
8282
pub globals: PyObjectRef,
8383
}
8484

85+
impl fmt::Debug for Scope {
86+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87+
// TODO: have a more informative Debug impl that DOESN'T recurse and cause a stack overflow
88+
f.write_str("Scope")
89+
}
90+
}
91+
8592
impl Scope {
8693
pub fn new(locals: Option<PyObjectRef>, globals: PyObjectRef) -> Scope {
8794
let locals = match locals {
@@ -99,10 +106,7 @@ impl Scope {
99106
}
100107

101108
pub fn get_only_locals(&self) -> Option<PyObjectRef> {
102-
match self.locals.iter().next() {
103-
Some(dict) => Some(dict.clone()),
104-
None => None,
105-
}
109+
self.locals.iter().next().cloned()
106110
}
107111

108112
pub fn child_scope_with_locals(&self, locals: PyObjectRef) -> Scope {
@@ -1211,22 +1215,25 @@ impl fmt::Debug for Frame {
12111215
.stack
12121216
.borrow()
12131217
.iter()
1214-
.map(|elem| format!("\n > {:?}", elem))
1215-
.collect::<Vec<_>>()
1216-
.join("");
1218+
.map(|elem| {
1219+
if elem.payload.as_any().is::<Frame>() {
1220+
"\n > {frame}".to_string()
1221+
} else {
1222+
format!("\n > {:?}", elem)
1223+
}
1224+
})
1225+
.collect::<String>();
12171226
let block_str = self
12181227
.blocks
12191228
.borrow()
12201229
.iter()
12211230
.map(|elem| format!("\n > {:?}", elem))
1222-
.collect::<Vec<_>>()
1223-
.join("");
1231+
.collect::<String>();
12241232
let local_str = match self.scope.get_locals().payload::<PyDict>() {
12251233
Some(dict) => objdict::get_key_value_pairs_from_content(&dict.entries.borrow())
12261234
.iter()
12271235
.map(|elem| format!("\n {:?} = {:?}", elem.0, elem.1))
1228-
.collect::<Vec<_>>()
1229-
.join(""),
1236+
.collect::<String>(),
12301237
None => panic!("locals unexpectedly not wrapping a dict!",),
12311238
};
12321239
write!(

vm/src/obj/objdict.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use std::cell::{Cell, RefCell};
22
use std::collections::HashMap;
3+
use std::fmt;
34
use std::ops::{Deref, DerefMut};
45

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

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

17-
#[derive(Default, Debug)]
18+
#[derive(Default)]
1819
pub struct PyDict {
1920
// TODO: should be private
2021
pub entries: RefCell<DictContentType>,
2122
}
2223
pub type PyDictRef = PyRef<PyDict>;
2324

25+
impl fmt::Debug for PyDict {
26+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27+
// TODO: implement more detailed, non-recursive Debug formatter
28+
f.write_str("dict")
29+
}
30+
}
31+
2432
impl PyValue for PyDict {
2533
fn required_type(ctx: &PyContext) -> PyObjectRef {
2634
ctx.dict_type()

vm/src/obj/objlist.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,21 @@ use crate::pyobject::{
1414
};
1515
use crate::vm::{ReprGuard, VirtualMachine};
1616
use num_traits::ToPrimitive;
17+
use std::fmt;
1718

18-
#[derive(Debug, Default)]
19+
#[derive(Default)]
1920
pub struct PyList {
2021
// TODO: shouldn't be public
2122
pub elements: RefCell<Vec<PyObjectRef>>,
2223
}
2324

25+
impl fmt::Debug for PyList {
26+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27+
// TODO: implement more detailed, non-recursive Debug formatter
28+
f.write_str("list")
29+
}
30+
}
31+
2432
impl From<Vec<PyObjectRef>> for PyList {
2533
fn from(elements: Vec<PyObjectRef>) -> Self {
2634
PyList {

vm/src/obj/objobject.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@ use super::objtype;
44
use crate::obj::objproperty::PropertyBuilder;
55
use crate::pyobject::{
66
AttributeProtocol, DictProtocol, IdProtocol, PyAttributes, PyContext, PyFuncArgs, PyObjectRef,
7-
PyRef, PyResult, TypeProtocol,
7+
PyRef, PyResult, PyValue, TypeProtocol,
88
};
99
use crate::vm::VirtualMachine;
1010

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

14+
impl PyValue for PyInstance {
15+
fn required_type(ctx: &PyContext) -> PyObjectRef {
16+
ctx.object()
17+
}
18+
}
19+
1420
pub type PyInstanceRef = PyRef<PyInstance>;
1521

1622
pub fn new_instance(vm: &mut VirtualMachine, mut args: PyFuncArgs) -> PyResult {

vm/src/obj/objset.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
*/
44

55
use std::cell::{Cell, RefCell};
6-
use std::collections::hash_map::DefaultHasher;
7-
use std::collections::HashMap;
6+
use std::collections::{hash_map::DefaultHasher, HashMap};
7+
use std::fmt;
88
use std::hash::{Hash, Hasher};
99

1010
use super::objbool;
@@ -17,11 +17,18 @@ use crate::pyobject::{
1717
};
1818
use crate::vm::{ReprGuard, VirtualMachine};
1919

20-
#[derive(Debug, Default)]
20+
#[derive(Default)]
2121
pub struct PySet {
2222
elements: RefCell<HashMap<u64, PyObjectRef>>,
2323
}
2424

25+
impl fmt::Debug for PySet {
26+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
27+
// TODO: implement more detailed, non-recursive Debug formatter
28+
f.write_str("set")
29+
}
30+
}
31+
2532
impl PyValue for PySet {
2633
fn required_type(ctx: &PyContext) -> PyObjectRef {
2734
ctx.set_type()

vm/src/obj/objtuple.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use std::cell::{Cell, RefCell};
2+
use std::fmt;
23
use std::hash::{Hash, Hasher};
34

45
use crate::pyobject::{
@@ -15,13 +16,20 @@ use super::objsequence::{
1516
use super::objstr;
1617
use super::objtype;
1718

18-
#[derive(Debug, Default)]
19+
#[derive(Default)]
1920
pub struct PyTuple {
2021
// TODO: shouldn't be public
2122
// TODO: tuples are immutable, remove this RefCell
2223
pub elements: RefCell<Vec<PyObjectRef>>,
2324
}
2425

26+
impl fmt::Debug for PyTuple {
27+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
28+
// TODO: implement more informational, non-recursive Debug formatter
29+
f.write_str("tuple")
30+
}
31+
}
32+
2533
impl From<Vec<PyObjectRef>> for PyTuple {
2634
fn from(elements: Vec<PyObjectRef>) -> Self {
2735
PyTuple {

vm/src/pyobject.rs

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -623,11 +623,7 @@ impl PyContext {
623623
}
624624

625625
pub fn new_instance(&self, class: PyObjectRef, dict: Option<PyAttributes>) -> PyObjectRef {
626-
let dict = if let Some(dict) = dict {
627-
dict
628-
} else {
629-
PyAttributes::new()
630-
};
626+
let dict = dict.unwrap_or_default();
631627
PyObject {
632628
typ: class,
633629
dict: Some(RefCell::new(dict)),
@@ -697,7 +693,7 @@ impl Default for PyContext {
697693
pub struct PyObject {
698694
pub typ: PyObjectRef,
699695
pub dict: Option<RefCell<PyAttributes>>, // __dict__ member
700-
pub payload: Box<dyn Any>,
696+
pub payload: Box<dyn PyObjectPayload>,
701697
}
702698

703699
/// A reference to a Python object.
@@ -1557,7 +1553,7 @@ impl PyValue for PyIteratorValue {
15571553
}
15581554

15591555
impl PyObject {
1560-
pub fn new<T: PyValue>(payload: T, typ: PyObjectRef) -> PyObjectRef {
1556+
pub fn new<T: PyObjectPayload>(payload: T, typ: PyObjectRef) -> PyObjectRef {
15611557
PyObject {
15621558
typ,
15631559
dict: Some(RefCell::new(PyAttributes::new())),
@@ -1571,14 +1567,13 @@ impl PyObject {
15711567
Rc::new(self)
15721568
}
15731569

1570+
#[inline]
15741571
pub fn payload<T: PyValue>(&self) -> Option<&T> {
1575-
self.payload.downcast_ref()
1572+
self.payload.as_any().downcast_ref()
15761573
}
15771574
}
15781575

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

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

1601+
pub trait PyObjectPayload: Any + fmt::Debug + 'static {
1602+
fn as_any(&self) -> &dyn Any;
1603+
}
1604+
1605+
impl<T: PyValue + 'static> PyObjectPayload for T {
1606+
#[inline]
1607+
fn as_any(&self) -> &dyn Any {
1608+
self
1609+
}
1610+
}
1611+
16061612
impl FromPyObjectRef for PyRef<PyClass> {
16071613
fn from_pyobj(obj: &PyObjectRef) -> Self {
16081614
if let Some(_) = obj.payload::<PyClass>() {

vm/src/stdlib/re.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,15 +197,15 @@ fn match_end(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
197197
/// Retrieve inner rust regex from python object:
198198
fn get_regex<'a>(obj: &'a PyObjectRef) -> &'a Regex {
199199
// TODO: Regex shouldn't be stored in payload directly, create newtype wrapper
200-
if let Some(regex) = obj.payload.downcast_ref::<Regex>() {
200+
if let Some(regex) = obj.payload::<Regex>() {
201201
return regex;
202202
}
203203
panic!("Inner error getting regex {:?}", obj);
204204
}
205205

206206
/// Retrieve inner rust match from python object:
207207
fn get_match<'a>(obj: &'a PyObjectRef) -> &'a PyMatch {
208-
if let Some(value) = obj.payload.downcast_ref::<PyMatch>() {
208+
if let Some(value) = obj.payload::<PyMatch>() {
209209
return value;
210210
}
211211
panic!("Inner error getting match {:?}", obj);

wasm/lib/src/browser_module.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl PyPromise {
171171
}
172172

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

0 commit comments

Comments
 (0)