File
を渡してWebAssemblyメモリコンテキスト内で読み取るにはどうすればよいですか?
JavaScriptを使用してブラウザでファイルを読み取るのは簡単です。
<input class="file-selector" type="file" id="files" name="files[]" />
bootstrap WebAssemblyコードをRust with the crate stdweb で記述し、イベントリスナーをDOM要素に追加して起動することができましたup 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
}));
JavaScriptでは、要素からファイルを取得してリーダーに渡しますが、stdwebのAPIには次の署名が必要です。
pub fn read_as_array_buffer<T: IBlob>(&self, blob: &T) -> Result<(), TODO>
IBlob
を実装する方法がわかりません。また、stdweb APIを使用するか、WebAssembly/Rustを理解しているときに、明らかな何かが欠けていると確信しています。 TF-8に変換する よりも冗長ではないものがあることを期待していました。
FileReader
自体がJavaScriptからWebAssemblyに渡されるときに機能します。とにかくデータをJavaScriptAPIで読み取る必要があるため、これはクリーンなアプローチのようにも思えます。WASMからJSを呼び出す必要はありません。
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();
}
私はなんとかファイルオブジェクトにアクセスし、それを次の方法で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| {
let file = js!{return @{&file_input_element}.files[0]};
let real_file: stdweb::web::Blob = file.try_into().unwrap();
reader.read_as_text(&real_file);
}
_
このコードはコンパイルされます。ただし、データがreader.result()
を介して利用可能になることはありません。