Skip to content

Commit a6f3b9a

Browse files
committed
Add PyCallable
1 parent 2a74e48 commit a6f3b9a

File tree

3 files changed

+59
-22
lines changed

3 files changed

+59
-22
lines changed

vm/src/pyobject.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -878,6 +878,39 @@ where
878878
}
879879
}
880880

881+
#[derive(Clone)]
882+
pub struct PyCallable {
883+
obj: PyObjectRef,
884+
}
885+
886+
impl PyCallable {
887+
#[inline]
888+
pub fn invoke(&self, args: impl Into<PyFuncArgs>, vm: &VirtualMachine) -> PyResult {
889+
vm.invoke(self.obj.clone(), args)
890+
}
891+
892+
#[inline]
893+
pub fn into_object(self) -> PyObjectRef {
894+
self.obj
895+
}
896+
}
897+
898+
impl TryFromObject for PyCallable {
899+
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
900+
if vm.is_callable(&obj) {
901+
Ok(PyCallable { obj })
902+
} else {
903+
Err(vm.new_type_error(format!("'{}' object is not callable", obj.class().name)))
904+
}
905+
}
906+
}
907+
908+
impl IntoPyObject for PyCallable {
909+
fn into_pyobject(self, _vm: &VirtualMachine) -> PyResult {
910+
Ok(self.into_object())
911+
}
912+
}
913+
881914
pub trait IdProtocol {
882915
fn get_id(&self) -> usize;
883916
fn is<T>(&self, other: &T) -> bool

vm/src/vm.rs

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -341,11 +341,7 @@ impl VirtualMachine {
341341
}
342342
}
343343

344-
pub fn invoke<T>(&self, func_ref: PyObjectRef, args: T) -> PyResult
345-
where
346-
T: Into<PyFuncArgs>,
347-
{
348-
let args = args.into();
344+
fn _invoke(&self, func_ref: PyObjectRef, args: PyFuncArgs) -> PyResult {
349345
trace!("Invoke: {:?} {:?}", func_ref, args);
350346
if let Some(PyFunction {
351347
ref code,
@@ -354,22 +350,29 @@ impl VirtualMachine {
354350
ref kw_only_defaults,
355351
}) = func_ref.payload()
356352
{
357-
return self.invoke_python_function(code, scope, defaults, kw_only_defaults, args);
358-
}
359-
if let Some(PyMethod {
353+
self.invoke_python_function(code, scope, defaults, kw_only_defaults, args)
354+
} else if let Some(PyMethod {
360355
ref function,
361356
ref object,
362357
}) = func_ref.payload()
363358
{
364-
return self.invoke(function.clone(), args.insert(object.clone()));
365-
}
366-
if let Some(PyBuiltinFunction { ref value }) = func_ref.payload() {
367-
return value(self, args);
359+
self.invoke(function.clone(), args.insert(object.clone()))
360+
} else if let Some(PyBuiltinFunction { ref value }) = func_ref.payload() {
361+
value(self, args)
362+
} else {
363+
// TODO: is it safe to just invoke __call__ otherwise?
364+
trace!("invoke __call__ for: {:?}", &func_ref.payload);
365+
self.call_method(&func_ref, "__call__", args)
368366
}
367+
}
369368

370-
// TODO: is it safe to just invoke __call__ otherwise?
371-
trace!("invoke __call__ for: {:?}", &func_ref.payload);
372-
self.call_method(&func_ref, "__call__", args)
369+
// TODO: make func_ref an &PyObjectRef
370+
#[inline]
371+
pub fn invoke<T>(&self, func_ref: PyObjectRef, args: T) -> PyResult
372+
where
373+
T: Into<PyFuncArgs>,
374+
{
375+
self._invoke(func_ref, args.into())
373376
}
374377

375378
fn invoke_python_function(

wasm/lib/src/browser_module.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ use wasm_bindgen_futures::{future_to_promise, JsFuture};
77

88
use rustpython_vm::function::{OptionalArg, PyFuncArgs};
99
use rustpython_vm::obj::{
10-
objdict::PyDictRef, objfunction::PyFunctionRef, objint::PyIntRef, objstr::PyStringRef,
11-
objtype::PyClassRef,
10+
objdict::PyDictRef, objint::PyIntRef, objstr::PyStringRef, objtype::PyClassRef,
11+
};
12+
use rustpython_vm::pyobject::{
13+
PyCallable, PyClassImpl, PyObject, PyObjectRef, PyRef, PyResult, PyValue,
1214
};
13-
use rustpython_vm::pyobject::{PyClassImpl, PyObject, PyObjectRef, PyRef, PyResult, PyValue};
1415
use rustpython_vm::VirtualMachine;
1516

1617
use crate::{convert, vm_class::weak_vm, wasm_builtins::window};
@@ -113,7 +114,7 @@ fn browser_fetch(url: PyStringRef, args: FetchArgs, vm: &VirtualMachine) -> PyRe
113114
Ok(PyPromise::from_future(future).into_ref(vm).into_object())
114115
}
115116

116-
fn browser_request_animation_frame(func: PyFunctionRef, vm: &VirtualMachine) -> PyResult {
117+
fn browser_request_animation_frame(func: PyCallable, vm: &VirtualMachine) -> PyResult {
117118
use std::{cell::RefCell, rc::Rc};
118119

119120
// this basic setup for request_animation_frame taken from:
@@ -192,8 +193,8 @@ impl PyPromise {
192193
#[pymethod]
193194
fn then(
194195
&self,
195-
on_fulfill: PyFunctionRef,
196-
on_reject: OptionalArg<PyFunctionRef>,
196+
on_fulfill: PyCallable,
197+
on_reject: OptionalArg<PyCallable>,
197198
vm: &VirtualMachine,
198199
) -> PyPromiseRef {
199200
let weak_vm = weak_vm(vm);
@@ -224,7 +225,7 @@ impl PyPromise {
224225
}
225226

226227
#[pymethod]
227-
fn catch(&self, on_reject: PyFunctionRef, vm: &VirtualMachine) -> PyPromiseRef {
228+
fn catch(&self, on_reject: PyCallable, vm: &VirtualMachine) -> PyPromiseRef {
228229
let weak_vm = weak_vm(vm);
229230

230231
let ret_future = JsFuture::from(self.value.clone()).then(move |res| {

0 commit comments

Comments
 (0)