Skip to content

Commit 7218d1d

Browse files
committed
Make more dyn Fn()s threading-optional
1 parent 4d8ffc7 commit 7218d1d

File tree

7 files changed

+40
-57
lines changed

7 files changed

+40
-57
lines changed

vm/src/function.rs

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ use crate::exceptions::PyBaseExceptionRef;
99
use crate::obj::objtuple::PyTupleRef;
1010
use crate::obj::objtype::{isinstance, PyClassRef};
1111
use crate::pyobject::{
12-
BorrowValue, IntoPyResult, PyObjectRef, PyRef, PyResult, PyValue, TryFromObject, TypeProtocol,
12+
BorrowValue, IntoPyResult, PyObjectRef, PyRef, PyResult, PyThreadingConstraint, PyValue,
13+
TryFromObject, TypeProtocol,
1314
};
1415
use crate::vm::VirtualMachine;
1516

@@ -476,15 +477,8 @@ tuple_from_py_func_args!(A, B, C, D);
476477
tuple_from_py_func_args!(A, B, C, D, E);
477478
tuple_from_py_func_args!(A, B, C, D, E, F);
478479

479-
// can't use PyThreadingConstraint for this since it's not an auto trait, and therefore we can't
480-
// add it ad-hoc to a trait object
481-
#[cfg(not(feature = "threading"))]
482-
pub type NativeFuncObj = dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static;
483-
#[cfg(feature = "threading")]
484-
pub type NativeFuncObj = dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult + Send + Sync + 'static;
485-
486480
/// A built-in Python function.
487-
pub type PyNativeFunc = Box<NativeFuncObj>;
481+
pub type PyNativeFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyFuncArgs) -> PyResult)>;
488482

489483
/// Implemented by types that are or can generate built-in functions.
490484
///
@@ -500,7 +494,7 @@ pub type PyNativeFunc = Box<NativeFuncObj>;
500494
///
501495
/// A bare `PyNativeFunc` also implements this trait, allowing the above to be
502496
/// done manually, for rare situations that don't fit into this model.
503-
pub trait IntoPyNativeFunc<T, R, VM>: Sized + Send + Sync + 'static {
497+
pub trait IntoPyNativeFunc<T, R, VM>: Sized + PyThreadingConstraint + 'static {
504498
fn call(&self, vm: &VirtualMachine, args: PyFuncArgs) -> PyResult;
505499
fn into_func(self) -> PyNativeFunc {
506500
Box::new(move |vm: &VirtualMachine, args| self.call(vm, args))
@@ -509,7 +503,7 @@ pub trait IntoPyNativeFunc<T, R, VM>: Sized + Send + Sync + 'static {
509503

510504
impl<F> IntoPyNativeFunc<PyFuncArgs, PyResult, VirtualMachine> for F
511505
where
512-
F: Fn(&VirtualMachine, PyFuncArgs) -> PyResult + 'static + Send + Sync,
506+
F: Fn(&VirtualMachine, PyFuncArgs) -> PyResult + PyThreadingConstraint + 'static,
513507
{
514508
fn call(&self, vm: &VirtualMachine, args: PyFuncArgs) -> PyResult {
515509
(self)(vm, args)
@@ -527,7 +521,7 @@ macro_rules! into_py_native_func_tuple {
527521
($(($n:tt, $T:ident)),*) => {
528522
impl<F, $($T,)* R> IntoPyNativeFunc<($(OwnedParam<$T>,)*), R, VirtualMachine> for F
529523
where
530-
F: Fn($($T,)* &VirtualMachine) -> R + 'static + Send + Sync,
524+
F: Fn($($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
531525
$($T: FromArgs,)*
532526
R: IntoPyResult,
533527
{
@@ -540,7 +534,7 @@ macro_rules! into_py_native_func_tuple {
540534

541535
impl<F, S, $($T,)* R> IntoPyNativeFunc<(RefParam<S>, $(OwnedParam<$T>,)*), R, VirtualMachine> for F
542536
where
543-
F: Fn(&S, $($T,)* &VirtualMachine) -> R + 'static + Send + Sync,
537+
F: Fn(&S, $($T,)* &VirtualMachine) -> R + PyThreadingConstraint + 'static,
544538
S: PyValue,
545539
$($T: FromArgs,)*
546540
R: IntoPyResult,
@@ -554,7 +548,7 @@ macro_rules! into_py_native_func_tuple {
554548

555549
impl<F, $($T,)* R> IntoPyNativeFunc<($(OwnedParam<$T>,)*), R, ()> for F
556550
where
557-
F: Fn($($T,)*) -> R + 'static + Send + Sync,
551+
F: Fn($($T,)*) -> R + PyThreadingConstraint + 'static,
558552
$($T: FromArgs,)*
559553
R: IntoPyResult,
560554
{
@@ -567,7 +561,7 @@ macro_rules! into_py_native_func_tuple {
567561

568562
impl<F, S, $($T,)* R> IntoPyNativeFunc<(RefParam<S>, $(OwnedParam<$T>,)*), R, ()> for F
569563
where
570-
F: Fn(&S, $($T,)*) -> R + 'static + Send + Sync,
564+
F: Fn(&S, $($T,)*) -> R + PyThreadingConstraint + 'static,
571565
S: PyValue,
572566
$($T: FromArgs,)*
573567
R: IntoPyResult,
@@ -645,18 +639,16 @@ where
645639

646640
#[cfg(test)]
647641
mod tests {
642+
use super::*;
643+
648644
#[test]
649645
fn test_intonativefunc_noalloc() {
650-
macro_rules! check_size {
651-
($f:expr) => {
652-
let f = super::IntoPyNativeFunc::into_func(py_func);
653-
assert_eq!(std::mem::size_of_val(f.as_ref()), 0);
654-
};
655-
}
646+
let check_zst = |f: PyNativeFunc| assert_eq!(std::mem::size_of_val(f.as_ref()), 0);
656647
fn py_func(_b: bool, _vm: &crate::VirtualMachine) -> i32 {
657648
1
658649
}
659-
check_size!(py_func);
660-
check_size!(|| "foo".to_owned());
650+
check_zst(py_func.into_func());
651+
let empty_closure = || "foo".to_owned();
652+
check_zst(empty_closure.into_func());
661653
}
662654
}

vm/src/macros.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,3 +240,21 @@ macro_rules! named_function {
240240
}
241241
}};
242242
}
243+
244+
// can't use PyThreadingConstraint for stuff like this since it's not an auto trait, and
245+
// therefore we can't add it ad-hoc to a trait object
246+
cfg_if::cfg_if! {
247+
if #[cfg(feature = "threading")] {
248+
macro_rules! py_dyn_fn {
249+
(dyn Fn($($arg:ty),*$(,)*) -> $ret:ty) => {
250+
dyn Fn($($arg),*) -> $ret + Send + Sync + 'static
251+
};
252+
}
253+
} else {
254+
macro_rules! py_dyn_fn {
255+
(dyn Fn($($arg:ty),*$(,)*) -> $ret:ty) => {
256+
dyn Fn($($arg),*) -> $ret + 'static
257+
};
258+
}
259+
}
260+
}

vm/src/obj/objgetset.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ use crate::pyobject::{
1010
use crate::slots::SlotDescriptor;
1111
use crate::vm::VirtualMachine;
1212

13-
pub type PyGetterFunc = Box<dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult + Send + Sync>;
13+
pub type PyGetterFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef) -> PyResult)>;
1414
pub type PySetterFunc =
15-
Box<dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()> + Send + Sync>;
15+
Box<py_dyn_fn!(dyn Fn(&VirtualMachine, PyObjectRef, PyObjectRef) -> PyResult<()>)>;
1616

1717
pub trait IntoPyGetterFunc<T> {
1818
fn into_getter(self) -> PyGetterFunc;

vm/src/stdlib/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ mod winreg;
6868
#[cfg(not(any(target_arch = "wasm32", target_os = "redox")))]
6969
mod zlib;
7070

71-
pub type StdlibInitFunc = Box<dyn Fn(&VirtualMachine) -> PyObjectRef + Send + Sync>;
71+
pub type StdlibInitFunc = Box<py_dyn_fn!(dyn Fn(&VirtualMachine) -> PyObjectRef)>;
7272

7373
pub fn get_module_inits() -> HashMap<String, StdlibInitFunc> {
7474
#[allow(unused_mut)]

wasm/lib/src/convert.rs

Lines changed: 1 addition & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -17,31 +17,6 @@ use rustpython_vm::{exceptions, py_serde};
1717
use crate::browser_module;
1818
use crate::vm_class::{stored_vm_from_wasm, WASMVirtualMachine};
1919

20-
// Currently WASM do not support multithreading. We should change this once it is enabled.
21-
thread_local!(static JS_HANDLES: RefCell<Arena<JsValue>> = RefCell::new(Arena::new()));
22-
23-
pub struct JsHandle(generational_arena::Index);
24-
impl JsHandle {
25-
pub fn new(js: JsValue) -> Self {
26-
let idx = JS_HANDLES.with(|arena| arena.borrow_mut().insert(js));
27-
JsHandle(idx)
28-
}
29-
pub fn get(&self) -> JsValue {
30-
JS_HANDLES.with(|arena| {
31-
arena
32-
.borrow()
33-
.get(self.0)
34-
.expect("index was removed")
35-
.clone()
36-
})
37-
}
38-
}
39-
impl Drop for JsHandle {
40-
fn drop(&mut self) {
41-
JS_HANDLES.with(|arena| arena.borrow_mut().remove(self.0));
42-
}
43-
}
44-
4520
#[wasm_bindgen(inline_js = r"
4621
export class PyError extends Error {
4722
constructor(info) {
@@ -223,7 +198,7 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
223198
dict.into_object()
224199
}
225200
} else if js_val.is_function() {
226-
let js_handle = JsHandle::new(js_val);
201+
let func = js_sys::Function::from(js_val);
227202
vm.ctx
228203
.new_method(move |vm: &VirtualMachine, args: PyFuncArgs| -> PyResult {
229204
let this = Object::new();
@@ -235,7 +210,6 @@ pub fn js_to_py(vm: &VirtualMachine, js_val: JsValue) -> PyObjectRef {
235210
for v in args.args {
236211
js_args.push(&py_to_js(vm, v));
237212
}
238-
let func = js_sys::Function::from(js_handle.get());
239213
func.apply(&this, &js_args)
240214
.map(|val| js_to_py(vm, val))
241215
.map_err(|err| js_err_to_py_err(vm, &err))

wasm/lib/src/vm_class.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use rustpython_vm::scope::{NameProtocol, Scope};
1212
use rustpython_vm::{InitParameter, PySettings, VirtualMachine};
1313

1414
use crate::browser_module::setup_browser_module;
15-
use crate::convert::{self, JsHandle, PyResultExt};
15+
use crate::convert::{self, PyResultExt};
1616
use crate::js_module;
1717
use crate::wasm_builtins;
1818
use rustpython_compiler::mode::Mode;
@@ -227,9 +227,8 @@ impl WASMVirtualMachine {
227227
_ => return Err(error()),
228228
}
229229
} else if stdout.is_function() {
230-
let func_handle = JsHandle::new(stdout);
230+
let func = js_sys::Function::from(stdout);
231231
make_stdout_object(vm, move |data, vm| {
232-
let func = js_sys::Function::from(func_handle.get());
233232
func.call1(&JsValue::UNDEFINED, &data.into())
234233
.map_err(|err| convert::js_py_typeerror(vm, err))?;
235234
Ok(())

wasm/lib/src/wasm_builtins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ pub fn sys_stdout_write_console(data: &str, _vm: &VirtualMachine) -> PyResult<()
2121

2222
pub fn make_stdout_object(
2323
vm: &VirtualMachine,
24-
write_f: impl Fn(&str, &VirtualMachine) -> PyResult<()> + Send + Sync + 'static,
24+
write_f: impl Fn(&str, &VirtualMachine) -> PyResult<()> + 'static,
2525
) -> PyObjectRef {
2626
let ctx = &vm.ctx;
2727
let write_method = ctx.new_method(

0 commit comments

Comments
 (0)