Skip to content

Move weakref object type to obj module #636

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 2 commits into from
Mar 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions vm/src/obj/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ pub mod objstr;
pub mod objsuper;
pub mod objtuple;
pub mod objtype;
pub mod objweakref;
pub mod objzip;
50 changes: 50 additions & 0 deletions vm/src/obj/objweakref.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use crate::function::PyRef;
use crate::obj::objtype::PyClassRef;
use crate::pyobject::PyObjectPayload2;
use crate::pyobject::{PyContext, PyObject, PyObjectRef, PyResult};
use crate::vm::VirtualMachine;

use std::rc::{Rc, Weak};

#[derive(Debug)]
pub struct PyWeak {
referent: Weak<PyObject>,
}

impl PyWeak {
pub fn downgrade(obj: PyObjectRef) -> PyWeak {
PyWeak {
referent: Rc::downgrade(&obj),
}
}

pub fn upgrade(&self) -> Option<PyObjectRef> {
self.referent.upgrade()
}
}

impl PyObjectPayload2 for PyWeak {
fn required_type(ctx: &PyContext) -> PyObjectRef {
ctx.weakref_type()
}
}

pub type PyWeakRef = PyRef<PyWeak>;

impl PyWeakRef {
// TODO callbacks
fn create(cls: PyClassRef, referent: PyObjectRef, vm: &mut VirtualMachine) -> PyResult<Self> {
Self::new_with_type(vm, PyWeak::downgrade(referent), cls)
}

fn call(self, vm: &mut VirtualMachine) -> PyObjectRef {
self.referent.upgrade().unwrap_or_else(|| vm.get_none())
}
}

pub fn init(context: &PyContext) {
extend_class!(context, &context.weakref_type, {
"__new__" => context.new_rustfunc(PyWeakRef::create),
"__call__" => context.new_rustfunc(PyWeakRef::call)
});
}
24 changes: 13 additions & 11 deletions vm/src/pyobject.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::collections::HashMap;
use std::fmt;
use std::iter;
use std::ops::RangeInclusive;
use std::rc::{Rc, Weak};
use std::rc::Rc;

use num_bigint::BigInt;
use num_bigint::ToBigInt;
Expand Down Expand Up @@ -43,6 +43,7 @@ use crate::obj::objstr;
use crate::obj::objsuper;
use crate::obj::objtuple::{self, PyTuple};
use crate::obj::objtype::{self, PyClass};
use crate::obj::objweakref;
use crate::obj::objzip;
use crate::vm::VirtualMachine;

Expand All @@ -67,9 +68,6 @@ Basically reference counting, but then done by rust.
/// to the python object by 1.
pub type PyObjectRef = Rc<PyObject>;

/// Same as PyObjectRef, except for being a weak reference.
pub type PyObjectWeakRef = Weak<PyObject>;

/// Use this type for function which return a python object or and exception.
/// Both the python object and the python exception are `PyObjectRef` types
/// since exceptions are also python objects.
Expand Down Expand Up @@ -141,6 +139,7 @@ pub struct PyContext {
pub readonly_property_type: PyObjectRef,
pub module_type: PyObjectRef,
pub bound_method_type: PyObjectRef,
pub weakref_type: PyObjectRef,
pub object: PyObjectRef,
pub exceptions: exceptions::ExceptionZoo,
}
Expand Down Expand Up @@ -185,6 +184,7 @@ impl PyContext {
let readonly_property_type =
create_type("readonly_property", &type_type, &object_type, &dict_type);
let super_type = create_type("super", &type_type, &object_type, &dict_type);
let weakref_type = create_type("ref", &type_type, &object_type, &dict_type);
let generator_type = create_type("generator", &type_type, &object_type, &dict_type);
let bound_method_type = create_type("method", &type_type, &object_type, &dict_type);
let str_type = create_type("str", &type_type, &object_type, &dict_type);
Expand Down Expand Up @@ -284,6 +284,7 @@ impl PyContext {
generator_type,
module_type,
bound_method_type,
weakref_type,
type_type,
exceptions,
};
Expand Down Expand Up @@ -316,6 +317,7 @@ impl PyContext {
objbool::init(&context);
objcode::init(&context);
objframe::init(&context);
objweakref::init(&context);
objnone::init(&context);
objmodule::init(&context);
exceptions::init(&context);
Expand Down Expand Up @@ -450,6 +452,10 @@ impl PyContext {
self.bound_method_type.clone()
}

pub fn weakref_type(&self) -> PyObjectRef {
self.weakref_type.clone()
}

pub fn type_type(&self) -> PyObjectRef {
self.type_type.clone()
}
Expand All @@ -465,6 +471,7 @@ impl PyContext {
pub fn not_implemented(&self) -> PyObjectRef {
self.not_implemented.clone()
}

pub fn object(&self) -> PyObjectRef {
self.object.clone()
}
Expand Down Expand Up @@ -1481,7 +1488,6 @@ into_py_native_func_tuple!((a, A), (b, B), (c, C), (d, D), (e, E));
/// of rust data for a particular python object. Determine the python type
/// by using for example the `.typ()` method on a python object.
pub enum PyObjectPayload {
WeakRef { referent: PyObjectWeakRef },
AnyRustValue { value: Box<dyn std::any::Any> },
}

Expand Down Expand Up @@ -1510,7 +1516,6 @@ impl PyObjectPayload2 for PyIteratorValue {
impl fmt::Debug for PyObjectPayload {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
PyObjectPayload::WeakRef { .. } => write!(f, "weakref"),
PyObjectPayload::AnyRustValue { value } => value.fmt(f),
}
}
Expand All @@ -1532,11 +1537,8 @@ impl PyObject {
}

pub fn payload<T: PyObjectPayload2>(&self) -> Option<&T> {
if let PyObjectPayload::AnyRustValue { ref value } = self.payload {
value.downcast_ref()
} else {
None
}
let PyObjectPayload::AnyRustValue { ref value } = self.payload;
value.downcast_ref()
}
}

Expand Down
15 changes: 7 additions & 8 deletions vm/src/stdlib/re.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,20 +191,19 @@ 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 {
if let PyObjectPayload::AnyRustValue { ref value } = obj.payload {
if let Some(regex) = value.downcast_ref::<Regex>() {
return regex;
}
// TODO: Regex shouldn't be stored in payload directly, create newtype wrapper
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
if let Some(regex) = value.downcast_ref::<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 PyObjectPayload::AnyRustValue { ref value } = obj.payload {
if let Some(value) = value.downcast_ref::<PyMatch>() {
return value;
}
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
if let Some(value) = value.downcast_ref::<PyMatch>() {
return value;
}
panic!("Inner error getting match {:?}", obj);
}
7 changes: 3 additions & 4 deletions vm/src/stdlib/socket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -127,10 +127,9 @@ impl Socket {
}

fn get_socket<'a>(obj: &'a PyObjectRef) -> impl DerefMut<Target = Socket> + 'a {
if let PyObjectPayload::AnyRustValue { ref value } = obj.payload {
if let Some(socket) = value.downcast_ref::<RefCell<Socket>>() {
return socket.borrow_mut();
}
let PyObjectPayload::AnyRustValue { ref value } = obj.payload;
if let Some(socket) = value.downcast_ref::<RefCell<Socket>>() {
return socket.borrow_mut();
}
panic!("Inner error getting socket {:?}", obj);
}
Expand Down
45 changes: 2 additions & 43 deletions vm/src/stdlib/weakref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,51 +5,10 @@
//! - [rust weak struct](https://doc.rust-lang.org/std/rc/struct.Weak.html)
//!

use crate::pyobject::{
PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyObjectWeakRef, PyResult,
TypeProtocol,
};
use crate::VirtualMachine;
use std::rc::Rc;
use super::super::pyobject::{PyContext, PyObjectRef};

pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
let py_ref_class = py_class!(ctx, "ref", ctx.object(), {
"__new__" => ctx.new_rustfunc(ref_new),
"__call__" => ctx.new_rustfunc(ref_call)
});

py_module!(ctx, "_weakref", {
"ref" => py_ref_class
"ref" => ctx.weakref_type()
})
}

fn ref_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
// TODO: check first argument for subclass of `ref`.
arg_check!(vm, args, required = [(cls, None), (referent, None)]);
let referent = Rc::downgrade(referent);
Ok(PyObject::new(
PyObjectPayload::WeakRef { referent },
cls.clone(),
))
}

/// Dereference the weakref, and check if we still refer something.
fn ref_call(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
// TODO: check first argument for subclass of `ref`.
arg_check!(vm, args, required = [(cls, None)]);
let referent = get_value(cls);
let py_obj = if let Some(obj) = referent.upgrade() {
obj
} else {
vm.get_none()
};
Ok(py_obj)
}

fn get_value(obj: &PyObjectRef) -> PyObjectWeakRef {
if let PyObjectPayload::WeakRef { referent } = &obj.payload {
referent.clone()
} else {
panic!("Inner error getting weak ref {:?}", obj);
}
}