Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to read a file with JavaScript to WebAssembly using Rust?

How can I pass a File to be read within the WebAssembly memory context?

Reading a file in the browser with JavaScript is easy:

<input class="file-selector" type="file" id="files" name="files[]" />

I was able to bootstrap WebAssembly code written in Rust with the crate stdweb, add an event listener to the DOM element and fire up a FileReader:

let reader = FileReader::new();
let file_input_element: InputElement = document().query_selector(".file-selector").unwrap().unwrap().try_into().unwrap();
file_input_element.add_event_listener(enclose!( (reader, file_input_element) move |event: InputEvent| {
    // mystery part
}));

In JavaScript, I would get the file from the element and pass it to the reader, however, the API of stdweb needs the following signature:

pub fn read_as_array_buffer<T: IBlob>(&self, blob: &T) -> Result<(), TODO>

I have no idea how to implement IBlob and I am sure that I am missing something obvious either with the stdweb API or in my understanding of WebAssembly/Rust. I was hoping that there is something less verbose than converting stuff to UTF-8.

like image 248
Journeycorner Avatar asked Jun 26 '18 16:06

Journeycorner


People also ask

Can JavaScript compile to WebAssembly?

With around 40 languages that can compile to WebAssembly, developers can finally use their favorite language on the Web. WebAssembly does not replace JavaScript; in fact, some JavaScript code is required to load WebAssembly modules. WebAssembly runs in all major browsers and in all platforms.

How do I use JavaScript with Rust?

To call Rust from JavaScript, you need to compile the Rust code to Wasm and provide the thin JavaScript wrapper. The template project already has it configured. You only need to use the wasm-bindgen macro on the Rust functions you want to make available.

Can WebAssembly access file system?

The WebAssembly VM provides a sandbox to ensure application safety. However, this sandbox is also a very limited “computer” that has no concept of file system, network, or even a clock or timer. That is very limiting for the Rust programs running inside WebAssembly.

Is Rust WebAssembly faster than JavaScript?

Wasm is 1.15-1.67 times faster than JavaScript on Google Chrome on a desktop.


1 Answers

It works when the FileReader itself is passed from JavaScript to WebAssembly. It also seems like a clean approach because the data has to be read by the JavaScript API anyway - no need to call JS from WASM.

index.html

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Read to wasm</title>
</head>
<body>
<input type="file" id="file-input"/>
<script src="reader.js"></script>
<script>
    var fileReader = new FileReader();
    fileReader.onloadend = e => Rust.reader
            .then(reader=> {
                window.alert(reader.print_result(fileReader));
            });

    var fileInputElement = document.getElementById("file-input");
    fileInputElement.addEventListener("change", e => fileReader.readAsText(fileInputElement.files[0]));
</script>
</body>
</html>

main.rs

#![feature(proc_macro)]

#[macro_use]
extern crate stdweb;

use stdweb::js_export;
use stdweb::web::FileReader;
use stdweb::web::FileReaderResult;

#[js_export]
fn print_result(file_reader: FileReader) -> String {
    match file_reader.result() {
        Some(value) => match value {
            FileReaderResult::String(value) => value,
            _ => String::from("not a text"),
        }
        None => String::from("empty")
    }
}

fn main() {
    stdweb::initialize();

    stdweb::event_loop();
}
like image 86
Journeycorner Avatar answered Sep 23 '22 02:09

Journeycorner