Skip to content

Commit 2fc53a9

Browse files
Merge pull request RustPython#539 from coolreader18/wasm-browser-req_anim_frame
[WASM] Add requestAnimationFrame to browser module
2 parents aa48718 + 9066c73 commit 2fc53a9

File tree

2 files changed

+73
-9
lines changed

2 files changed

+73
-9
lines changed

wasm/demo/snippets/mandelbrot.py

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
1-
# NOTE: will take a while, up to around a minute, to run.
2-
# Expect this page to freeze.
1+
from browser import request_animation_frame
32

43
w = 50.0
54
h = 50.0
65

7-
y = 0.0
8-
while y < h:
6+
# to make up for the lack of `global`
7+
_y = {'y': 0.0}
8+
9+
def mandel(_time_elapsed=None):
10+
y = _y['y']
11+
if y >= h:
12+
return
913
x = 0.0
1014
while x < w:
1115
Zr, Zi, Tr, Ti = 0.0, 0.0, 0.0, 0.0
@@ -18,14 +22,17 @@
1822
Zr = Tr - Ti + Cr
1923
Tr = Zr * Zr
2024
Ti = Zi * Zi
21-
i = i + 1
25+
i += 1
2226

2327
if Tr + Ti <= 4:
2428
print('*', end='')
2529
else:
2630
print('·', end='')
2731

28-
x = x + 1
32+
x += 1
2933

3034
print()
31-
y = y + 1
35+
_y['y'] += 1
36+
request_animation_frame(mandel)
37+
38+
request_animation_frame(mandel)

wasm/lib/src/browser_module.rs

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{convert, vm_class::AccessibleVM, wasm_builtins::window};
22
use futures::{future, Future};
33
use js_sys::Promise;
4-
use rustpython_vm::obj::objstr;
4+
use rustpython_vm::obj::{objint, objstr};
55
use rustpython_vm::pyobject::{PyContext, PyFuncArgs, PyObjectRef, PyResult, TypeProtocol};
66
use rustpython_vm::VirtualMachine;
77
use wasm_bindgen::{prelude::*, JsCast};
@@ -125,11 +125,68 @@ fn browser_fetch(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
125125
Ok(vm.get_none())
126126
}
127127

128+
fn browser_request_animation_frame(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
129+
arg_check!(vm, args, required = [(func, Some(vm.ctx.function_type()))]);
130+
131+
use std::{cell::RefCell, rc::Rc};
132+
133+
// this basic setup for request_animation_frame taken from:
134+
// https://rustwasm.github.io/wasm-bindgen/examples/request-animation-frame.html
135+
136+
let f = Rc::new(RefCell::new(None));
137+
let g = f.clone();
138+
139+
let func = func.clone();
140+
141+
let acc_vm = AccessibleVM::from_vm(vm);
142+
143+
*g.borrow_mut() = Some(Closure::wrap(Box::new(move |time: f64| {
144+
let vm = &mut acc_vm
145+
.upgrade()
146+
.expect("that the vm is valid from inside of request_animation_frame");
147+
let func = func.clone();
148+
let args = PyFuncArgs {
149+
args: vec![vm.ctx.new_float(time)],
150+
kwargs: vec![],
151+
};
152+
let _ = vm.invoke(func, args);
153+
154+
let closure = f.borrow_mut().take();
155+
drop(closure);
156+
}) as Box<Fn(f64)>));
157+
158+
let id = window()
159+
.request_animation_frame(&js_sys::Function::from(
160+
g.borrow().as_ref().unwrap().as_ref().clone(),
161+
))
162+
.map_err(|err| convert::js_py_typeerror(vm, err))?;
163+
164+
Ok(vm.ctx.new_int(id))
165+
}
166+
167+
fn browser_cancel_animation_frame(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult {
168+
arg_check!(vm, args, required = [(id, Some(vm.ctx.int_type()))]);
169+
170+
// fine because
171+
let id = objint::get_value(id)
172+
.to_string()
173+
.parse()
174+
.expect("bigint.to_string() to be parsable as i32");
175+
176+
window()
177+
.cancel_animation_frame(id)
178+
.map_err(|err| convert::js_py_typeerror(vm, err))?;
179+
180+
Ok(vm.get_none())
181+
}
182+
128183
const BROWSER_NAME: &str = "browser";
129184

130185
pub fn mk_module(ctx: &PyContext) -> PyObjectRef {
131186
py_module!(ctx, BROWSER_NAME, {
132-
"fetch" => ctx.new_rustfunc(browser_fetch)
187+
"fetch" => ctx.new_rustfunc(browser_fetch),
188+
"request_animation_frame" => ctx.new_rustfunc(browser_request_animation_frame),
189+
"cancel_animation_frame" => ctx.new_rustfunc(browser_cancel_animation_frame),
133190
})
134191
}
135192

0 commit comments

Comments
 (0)