|
| 1 | +//! Implementation in line with the python `weakref` module. |
| 2 | +//! |
| 3 | +//! See also: |
| 4 | +//! - [python weakref module](https://docs.python.org/3/library/weakref.html) |
| 5 | +//! - [rust weak struct](https://doc.rust-lang.org/std/rc/struct.Weak.html) |
| 6 | +//! |
| 7 | +
|
| 8 | +use super::super::obj::objtype; |
| 9 | +use super::super::pyobject::{ |
| 10 | + AttributeProtocol, DictProtocol, PyContext, PyFuncArgs, PyObject, PyObjectKind, PyObjectRef, |
| 11 | + PyObjectWeakRef, PyResult, TypeProtocol, |
| 12 | +}; |
| 13 | +use super::super::VirtualMachine; |
| 14 | +use std::rc::Rc; |
| 15 | + |
| 16 | +pub fn mk_module(ctx: &PyContext) -> PyObjectRef { |
| 17 | + let py_mod = ctx.new_module(&"_weakref".to_string(), ctx.new_scope(None)); |
| 18 | + |
| 19 | + let py_ref_class = ctx.new_class("ref", ctx.object()); |
| 20 | + py_ref_class.set_attr("__new__", ctx.new_rustfunc(ref_new)); |
| 21 | + py_ref_class.set_attr("__call__", ctx.new_rustfunc(ref_call)); |
| 22 | + py_mod.set_item("ref", py_ref_class); |
| 23 | + py_mod |
| 24 | +} |
| 25 | + |
| 26 | +fn ref_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { |
| 27 | + // TODO: check first argument for subclass of `ref`. |
| 28 | + arg_check!(vm, args, required = [(cls, None), (referent, None)]); |
| 29 | + let referent = Rc::downgrade(referent); |
| 30 | + Ok(PyObject::new( |
| 31 | + PyObjectKind::WeakRef { referent: referent }, |
| 32 | + cls.clone(), |
| 33 | + )) |
| 34 | +} |
| 35 | + |
| 36 | +/// Dereference the weakref, and check if we still refer something. |
| 37 | +fn ref_call(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { |
| 38 | + // TODO: check first argument for subclass of `ref`. |
| 39 | + arg_check!(vm, args, required = [(cls, None)]); |
| 40 | + let referent = get_value(cls); |
| 41 | + let py_obj = if let Some(obj) = referent.upgrade() { |
| 42 | + obj |
| 43 | + } else { |
| 44 | + vm.get_none() |
| 45 | + }; |
| 46 | + Ok(py_obj) |
| 47 | +} |
| 48 | + |
| 49 | +fn get_value(obj: &PyObjectRef) -> PyObjectWeakRef { |
| 50 | + if let PyObjectKind::WeakRef { referent } = &obj.borrow().kind { |
| 51 | + referent.clone() |
| 52 | + } else { |
| 53 | + panic!("Inner error getting weak ref {:?}", obj); |
| 54 | + } |
| 55 | +} |
0 commit comments