Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wasm broken: panicked at 'called Result::unwrap() on an Err value: Custom { kind: Other, error: StringError("operation not supported on wasm yet") } #115

Closed
iceiix opened this issue Mar 3, 2019 · 10 comments
Labels
enhancement New feature or request help wanted Extra attention is needed

Comments

@iceiix
Copy link
Owner

iceiix commented Mar 3, 2019

#92 added support for compiling for the wasm32-unknown-unknown target for WebAssembly, but it fails to run, panicking with "operation not supported on wasm yet" - need to adapt all code to support wasm (or compile it out with #[cfg(not(target_arch = "wasm32"))]):

[Error] panicked at 'called `Result::unwrap()` on an `Err` value: Custom { kind: Other, error: StringError("operation not supported on wasm yet") }', src/libcore/result.rs:1009:5

Stack:

__wbg_new_a99726b0abef495b
__wbg_new_a99726b0abef495b@http://localhost:8080/bootstrap.js:59:103
wasm-stub@[wasm code]
<?>.wasm-function[console_error_panic_hook::hook::he1fad92af5701fc6]@[wasm code]
<?>.wasm-function[core::ops::function::Fn::call::hde3e92baaac0baf2]@[wasm code]
<?>.wasm-function[std::panicking::rust_panic_with_hook::h869ce4541d4e3554]@[wasm code]
<?>.wasm-function[std::panicking::continue_panic_fmt::h0ad726c0b188da91]@[wasm code]
<?>.wasm-function[rust_begin_unwind]@[wasm code]
<?>.wasm-function[core::panicking::panic_fmt::h4d67173bc68f6d5a]@[wasm code]
<?>.wasm-function[core::result::unwrap_failed::h69fb4e02ca2192a0]@[wasm code]
<?>.wasm-function[<core::result::Result<T, E>>::unwrap::h79a8a390611a2b6e]@[wasm code]
<?>.wasm-function[stevenarella::console::Vars::save_config::h541aec1a47a53665]@[wasm code]
<?>.wasm-function[stevenarella::main::hbc764074c370a7d5]@[wasm code]
<?>.wasm-function[main]@[wasm code]
wasm-stub@[wasm code]
main@[native code]
eval code
eval@[native code]
./index.js@http://localhost:8080/0.bootstrap.js:34:5
__webpack_require__@http://localhost:8080/bootstrap.js:90:34
__webpack_require__@[native code]
promiseReactionJob@[native code]


	__wbg_error_f7214ae7db04600c (stevenarella.js:38)
	__wbg_error_f7214ae7db04600c (bootstrap.js:65:106)
	wasm-stub
	<?>.wasm-function[console_error_panic_hook::hook::he1fad92af5701fc6]
	<?>.wasm-function[core::ops::function::Fn::call::hde3e92baaac0baf2]
	<?>.wasm-function[std::panicking::rust_panic_with_hook::h869ce4541d4e3554]
	<?>.wasm-function[std::panicking::continue_panic_fmt::h0ad726c0b188da91]
	<?>.wasm-function[rust_begin_unwind]
	<?>.wasm-function[core::panicking::panic_fmt::h4d67173bc68f6d5a]
	<?>.wasm-function[core::result::unwrap_failed::h69fb4e02ca2192a0]
	<?>.wasm-function[<core::result::Result<T, E>>::unwrap::h79a8a390611a2b6e]
	<?>.wasm-function[stevenarella::console::Vars::save_config::h541aec1a47a53665]
	<?>.wasm-function[stevenarella::main::hbc764074c370a7d5]
	<?>.wasm-function[main]
	wasm-stub
	main
	Eval Code
	eval
	./index.js (0.bootstrap.js:34)
	__webpack_require__ (bootstrap.js:90)
	__webpack_require__
	promiseReactionJob
[Error] Error importing `index.js`: – Error: Unreachable code should not be executed (evaluating 'stevenarella__WEBPACK_IMPORTED_MODULE_0__["main"]()')
Error: Unreachable code should not be executed (evaluating 'stevenarella__WEBPACK_IMPORTED_MODULE_0__["main"]()')
	(anonymous function)
	promiseReactionJob

This particular error appears to come from the Rust standard library: https://github.com/rust-lang/rust/blob/190feb65290d39d7ab6d44e994bd99188d339f16/src/libstd/sys/wasm/mod.rs#L70-L73

pub fn unsupported_err() -> crate::io::Error {
    crate::io::Error::new(crate::io::ErrorKind::Other,
                   "operation not supported on wasm yet")
}

from fs::File::create("conf.cfg") in src/console.mod.rs, relevant: https://stackoverflow.com/questions/53304832/loading-a-file-from-wasm. But once this particular issue is resolved, more incompatibilities will be uncovered, including in winit iceiix/winit#2 and glutin iceiix/glutin#1, which should wrap WebGL.

(Another option besides wasm32-unknown-unknown is wasm32-unknown-emscripten, which would fix File APIs because Emscripten has implementations for the web platform already, but Rust with Emscripten isn't as well supported: rust-windowing/winit#767 and https://rustwasm.github.io is all about wasm32-unknown-unknown, where the implementations are in pure Rust instead (albeit less complete at the moment).)

@iceiix iceiix added enhancement New feature or request help wanted Extra attention is needed labels Mar 3, 2019
@iceiix iceiix changed the title wasm: panicked at 'called Result::unwrap() on an Err value: Custom { kind: Other, error: StringError("operation not supported on wasm yet") } wasm broken: panicked at 'called Result::unwrap() on an Err value: Custom { kind: Other, error: StringError("operation not supported on wasm yet") } May 14, 2019
@iceiix
Copy link
Owner Author

iceiix commented May 15, 2019

It is instructive to see what other games are doing. Zemeroth posted this on their blog with many technical details: https://ozkriff.github.io/2019-05-13--devlog-zemeroth-v0-5/. For the rendering backend investigation (#34). They had a custom engine Häte2d but migrated to ggez and wrote some helpers on top for scene management and widgets. ggez "Good Game Easily" seems to be quite a well supported project with a lot of steam behind it. They used to use SDL2 (like Steven) but moved to winit with ggez 0.5-rc1. Unfortunately, ggez is 2D-only. Not in the running for a graphics backend replacement for this project.

For the math library, they were using cgmath but migrated to nalgebra, as that's what ggez uses. Steven uses cgmath. There is this post: Cgmath looking for new maintainers with some concern about the future of cgmath but it works well so I'm deciding against switching for now.

More interesting, WebAssembly support. Stuck on dependences myself. What did Zemeroth do? They use a separate crate called good-web-game which implements a subset of compatible API for wasm32-unknown-unknown, using WebGL1 and WebGL2 canvases. That's pretty cool. The blog post is worth reading to see how they substituted one crate for another depending on the target (wasm or not), having a different main() but much of the same code. This may be what has to be done in Stevenarella to replace crates with native dependencies with web-based equivalents.

iceiix added a commit that referenced this issue May 20, 2019
Updating the glutin dependency to a 0.21.0-based branch, based on the migration guide at:
https://gentz.rocks/posts/glutin-v0-21-0-migration-guide/

* Remove glutin::ContextTrait

* Create window with ContextBuilder instead of WindowedContext::new

* Add .window() accessor on WindowContext, since it now dereferences to Context

In order to not break wasm32-unknown-unknown compilation, a minor fork is used of glutin v0.21.0 and a corresponding version of winit: iceiix/glutin#1 iceiix/winit#2
 - with stubs to compile (but not run, see issue #115)
@iceiix
Copy link
Owner Author

iceiix commented May 22, 2019

https://www.reddit.com/r/rust/comments/8y3fei/how_do_modules_like_stdfs_and_stdnet_work_with/ confirms they don't. But an idea of how to adopt without rewriting, implement the same methods to replace what is needed in std, and conditionalize on imports. Then there is no need to change the Rust compiler to adopt the no-op implementations there. Something like this works:

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(target_arch = "wasm32")] {
        struct File {}
        impl File {
            fn open(_: &str) {
            }
        }
    } else {
        use std::fs::File;
    }
}

fn main() {
    let f = File::open("/tmp/a");
    println!("f = {:?}", f);
}

for both cargo run and cargo build --target wasm32-unknown-unknown. Similar pattern for other parts of the standard library.

The question then becomes how to implement it, essentially a web filesystem (etc). It has been done: https://github.com/emscripten-core/emscripten/blob/incoming/src/library_fs.js - perhaps port this code or at least the interesting bits. Alternatively, implement it from scratch. But surely this is not too much of an unusual requirement for someone else not to already have done the work.

stdweb's File? https://docs.rs/stdweb/0.4.17/stdweb/web/struct.File.html - nope, this doesn't work:

use cfg_if::cfg_if;

cfg_if! {
    if #[cfg(target_arch = "wasm32")] {
        use stdweb::web::File;
    } else {
        use std::fs::File;
    }
}

fn main() {
    let f = File::open("/tmp/a");
    println!("f = {:?}", f);
}

not the same API:

error[E0599]: no function or associated item named `open` found for type `stdweb::webapi::file::File` in the current scope
  --> src/main.rs:12:19
   |
12 |     let f = File::open("/tmp/a");
   |             ------^^^^
   |             |
   |             function or associated item not found in `stdweb::webapi::file::File`


@iceiix

This comment has been minimized.

@iceiix
Copy link
Owner Author

iceiix commented May 22, 2019

File operations are invoked very early when loading/saving the console settings:

    let con = Arc::new(Mutex::new(console::Console::new()));
    let (vars, vsync) = {
        let mut vars = console::Vars::new();
        vars.register(CL_BRAND);
        auth::register_vars(&mut vars);
        settings::register_vars(&mut vars);
        vars.load_config();     // ****** here
        vars.save_config();    // ******
        let vsync = *vars.get(settings::R_VSYNC);
        (Rc::new(vars), vsync)
    };

@iceiix
Copy link
Owner Author

iceiix commented May 22, 2019

There's a brand new target which may solve many of these problems: wasm32-wasi. Targets the WebAssembly System Interface: https://wasi.dev. Available only in nightly, but looks like basically what I'm looking for. To run there is a runtime: https://github.com/CraneStation/wasmtime/ which has an informative introduction to WASI https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-intro.md and a WASI tutorial: https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-tutorial.md. The examples given use the standard filesystem APIs and works on the web (with a polyfill, and off the web with some interesting capabilities-based sandboxing system), perfect.

Unfortunately the www/ setup, which I based on the rustwasm tutorials https://rustwasm.github.io/wasm-pack/book/, is all using wasm32-unknown-unknown, but they mention wasi in their weekly update: https://rustwasm.github.io/2019/03/28/this-week-in-rust-and-wasm-015.html to be standardized: https://hacks.mozilla.org/2019/03/standardizing-wasi-a-webassembly-system-interface/

Can wasm-pack target wasi?

Testing building with cargo +nightly build --target wasm32-wasi. At least much of the work to build for the other wasm32's should be reusable since I conditionalize on target_arch = "wasm32"

@iceiix
Copy link
Owner Author

iceiix commented May 22, 2019

cargo +nightly build --target wasm32-wasi fails with 31 import errors in glutin for some reason:

warning: dropping unsupported crate type `cdylib` for target `wasm32-wasi`

error[E0432]: unresolved import `glutin::VirtualKeyCode`
  --> src/ui/mod.rs:21:5
   |
21 | use glutin::VirtualKeyCode;
   |     ^^^^^^^^^^^^^^^^^^^^^^ no `VirtualKeyCode` in the root

error[E0432]: unresolved import `glutin::VirtualKeyCode`
 --> src/settings.rs:3:5
  |
3 | use glutin::VirtualKeyCode;
  |     ^^^^^^^^^^^^^^^^^^^^^^ no `VirtualKeyCode` in the root

error[E0433]: failed to resolve: could not find `EventsLoop` in `glutin`
   --> src/main.rs:222:35
    |
222 |     let mut events_loop = glutin::EventsLoop::new();
    |                                   ^^^^^^^^^^ could not find `EventsLoop` in `glutin`
...

probably due to iceiix/glutin@5ff18de, which keys off target_os = unknown instead of target_arch = wasm32?

iceiix added a commit that referenced this issue May 22, 2019
Logging from the `log` facade goes to the colorized in-game GUI console (opened with the backtick key), as well as standard output using `println!` on the native build. To make this work on the wasm build, web-sys is used to access the `console` object, to call `console.log`, `console.warn`, and so on corresponding to the log levels. Extends #92, fails later (see also #115) but now outputs the starting up message:

[main.rs:206][INFO] Starting steven

* Add println! logging to console.log on wasm

* Initialize logger before config (called 'console variables' for some reason) to avoid having to disable it to reach the first logging statement

* Add web-sys crate for browser console access, wasm32-only

* Refactor logger to call println_level on both web/native

* Add multiple log levels, console.warn etc., matching console_log crate

https://github.com/iamcodemaker/console_log#details
iceiix added a commit that referenced this issue May 23, 2019
Includes iceiix/glutin@1e48d32

Progress towards #115, fixes the missing glutin symbols when compiling
with cargo +nightly build --target wasm32-wasi
@iceiix
Copy link
Owner Author

iceiix commented May 23, 2019

Fixed glutin missing on wasm32-wasi in c6b753b but it requires a different entrypoint than wasm32-unknown-unknown:

error: entry symbol `main` defined multiple times
   --> src/main.rs:194:1
    |
194 | / pub fn main() {
195 | |     let opt = Opt::from_args();
196 | |
197 | |     set_panic_hook();
...   |
354 | |     }
355 | | }
    | |_^
    |
    = help: did you use #[no_mangle] on `fn main`? Use #[start] instead

actually, need to remove #[wasm_bindgen]

iceiix added a commit that referenced this issue May 23, 2019
From investigation for #115, now three targets:

- wasm32-unknown-unknown: build with `wasm-pack build`, uses
the #[wasm_bindgen] directive on main()

- wasm32-wasi: build with `cargo +nightly build --target wasm32-wasi`,
requires normal main()

- native targets: same as wasm32-wasi
@iceiix
Copy link
Owner Author

iceiix commented May 23, 2019

Fixed the compilation error so now can compile to both wasm32-unknown-unknown (run wasm-pack build) and wasm32-wasi (cargo +nightly build --target wasm32-wasi), but neither get very far when trying to run them.

Trying to execute with https://github.com/CraneStation/wasmtime:

wasmtime $ target/release/wasmtime ../steven/target/wasm32-wasi/debug/stevenarella.wasm
error while processing main module ../steven/target/wasm32-wasi/debug/stevenarella.wasm: Instantiation error: Link error: __wbindgen_placeholder__/__wbindgen_string_new: no provided import function

wasm_bindgen is a post-compilation step used by wasm-pack, a step missing here. Can wasm-pack (https://github.com/rustwasm/wasm-pack "📦✨ your favorite rust -> wasm workflow tool! ") target wasm32-wasi instead of wasm32-unknown-unknown? Asked in rustwasm/wasm-pack#654

@iceiix
Copy link
Owner Author

iceiix commented May 23, 2019

Note after the std::fs error (if src/console/mod.rs load_config/save_config are removed, or hypothetically if they are fixed to support a web virtual filesystem), next error is of course in glutin, the OpenGL wrapper which doesn't support WebGL yet (and winit the web):

stevenarella.js:44 panicked at 'not yet implemented: Glutin-Blank: Platform unsupported', /Users/admin/.cargo/git/checkouts/glutin-390166537a874d6b/1e48d32/glutin/src/platform/blank/mod.rs:32:9

makepaddev solved the GL compatibility issues in their app, very nice https://makepad.github.io/makepad/ works well - some details from comment in winit/870 how they did it:

I've been building a Rust Wasm cross platform editor UI (demo makepad.github.io/makepad/ repo github.com/makepad/makepad), and i still have Winit as a dependency in it for linux but i'm removing it as i progress because of general stability and features missing. I compile cleanly to wasm32/unknown/unknown without emscripten.

Missing features i implemented for makepad (solutions in my codebase):

  • Wasm32-unknown-unknown support
  • A 'block or not' bool on the event api, not have 2 different poll calls (see https://github.com/makepad/makepad/blob/master/render/src/cx_mtl.rs#L211(
  • Web compatible clipboard support API that also works on (web/mac only atm)
  • Same keyboard input method as web (so no virtual key translation please)
  • Web compatible text-input API with IME support (web/mac only atm)
  • No 'outside of window mouse delta only', weird winit feature i fail to see the point of.

All of these features are implemented in my codebase and if anyone working on winit needs a reference or a place to copy from or see how web compatibility was managed, feel free to take anything its all MIT.
Currently on my todo is to replace winit entirely and implement Linux and Win32 directly on platform APIs, but that will happen in the next few months so implementations for those platforms of the above features will arrive as well.

As i have such specific finegrained requirements for my platform abstraction and winit seems so far away from what i want/need i don't want to go back to using winit myself or make pull requests, but maybe i can provide a reference to implement some of these features along the way instead.

Looks promising, will be watching this app but they already solved these problems, could use their solutions but hopefully they'll be generalized into crates I can import instead of copying code, or better yet if winit/glutin grows native WebGL/HTML5 support...basically stuck here.

@iceiix iceiix closed this as completed in 836ab9f May 29, 2019
iceiix added a commit that referenced this issue Feb 1, 2020
* Add new web-based std::fs replacement, localstoragefs:

https://github.com/iceiix/localstoragefs

* Add std_or_web to switch between std::fs (native) or localstoragefs (web)

* Update www readme for new missing glutin/winit links, opens issue #171
iceiix added a commit that referenced this issue Feb 1, 2020
* Add new web-based std::fs replacement, localstoragefs:

https://github.com/iceiix/localstoragefs

* Add std_or_web to switch between std::fs (native) or localstoragefs (web)

* Update www readme for new missing glutin/winit links, opens issue #171
iceiix added a commit that referenced this issue Feb 1, 2020
* Add new web-based std::fs replacement, localstoragefs:

https://github.com/iceiix/localstoragefs

* Add std_or_web to switch between std::fs (native) or localstoragefs (web)

* Update www readme for new missing glutin/winit links, opens issue #171
iceiix added a commit that referenced this issue Feb 2, 2020
* Add new web-based std::fs replacement, localstoragefs:

https://github.com/iceiix/localstoragefs

* Add std_or_web to switch between std::fs (native) or localstoragefs (web)

* Update www readme for new missing glutin/winit links, opens issue #171
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant