cursive
cursive copied to clipboard
add wasm-backend using HTML canvas element
Add WebAssembly (WASM) backend to Cursive library
This PR adds a new backend to the Cursive library that allows it to be used in WebAssembly (WASM) environments. The new backend is implemented using the web-sys
, js-sys
crates and provides a way to run Cursive-based applications in the browser.
To use the new backend, simply enable the wasm-backend
feature in your Cargo.toml
file:
[dependencies]
cursive = { version = "0.16", features = ["wasm-backend"] }
I made sample project using this backend, so you can see how to use this new backend. repo link: https://github.com/genieCS/wretris project link: https://geniecs.github.io
Just a shallow, quick review; currently breaks builds due to changing default features.
thank you for taking a look:) I addressed what you mentioned
Thanks for the work!
My main concern is that the async
features:
- is non-additive since it changes the API
- seems tied to wasm (we could imagine an async loop without wasm).
To avoid these two points, I'd be open to a major bump for API changes if needed, maybe even making async the default way to run the loop (or an option regardless of backend).
@gyscos I made run as async. Could you have another look?
(I'm finally back from a family trip and have at last some time to look at this PR in more depth.)
Thanks for the updates and reactivity!
Looking at the code more, I think we can actually avoid breaking changes by adding a parallel code-path for async (rather than replacing the existing one). The current "sync" API could be defined as simply calling block_on
the async API, preserving compatibility with existing code, without duplicating (too much) logic (I wish this didn't require the futures
crate though).
The "bare minimum" would be to have async fn post_events_async()
, so users could re-build their own event loop (the various step
and run
methods are just convenient methods to remove some boilerplace, but could be re-implemented user-side).
EDIT: I tried to do that in a async-restricted
branch, but I have no idea how to test it and see if it works.
We could then, later, add the convenient equivalent.
It also looks like the sleep
behaviour should maybe be part of the backend instead - and this opens up the possibility of having other async methods from the backend (input? drawing? refresh?). At this point, post_events
will no longer be the only method with an async equivalent.
The main issue is having async in traits currently requires the async_trait
crate. The heap allocation per method from async-trait doesn't matter much when it's just to call run
(or even step
), but it might not be ideal for the Backend trait, especially for the many print
methods (potentially thousands per second).
On the other hand we're using dynamic dispatch for the backend (which makes it incompatible with the current async_fn_in_trait
proposal) so maybe we should just use async-trait
here, only making sleep
async at first, and maybe refresh/input later (but not the print methods).
As a side-question, I'm wondering if this wasm backend would work in a non-browser wasm environment (like wasmtime?). I suspect not, so I'd favor calling it wasm_browser
or wasm_js
or something else more indicative of the browser aspect.
Also, would it be possible to add a very simple example using this backend? I haven't found how to use wasm-pack with an example, so maybe a dedicated "example" crate would be simpler.
(I'm really sorry for the back-and-forth.)
@gyscos thank you for your time and effort to review this PR.
-
"wasm_js" or "wasm_browser" idea sounds good to me. I'll think more to rename it.
-
Promise can be executed only if it runs forefront. In your
async-restricted
branch, it is wrapped byfutures::executor::block_on
so it would not work. How about having duplicate sets ofsleep
,post_events
,run
,step
, ...etc with configuration option as my first draft?
regarding test, I'll make a simple project and let you know in a week
@gyscos I made a simple project(https://github.com/genieCS/hello-wasm) for tests.
- in
/
path, runwasm-pack build
- in
www/
path, runnpm run start
if you see "Hello from Rust!" in web console, it works.
@gyscos canvas is for browser but it would not be hard to make other wasm backends work. I'd like to work on implementing other backend as a separate PR.
regarding async_trait
, I agree that it would be more proper to put sleep in backend.
but for now, it's only sleep
, so how about keep current status and when we have more to change Backend trait related to async, change together?