0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebAssembly / WasmAdvent Calendar 2024

Day 12

AssemblyScriptからホスト側の関数をコールバックする

Last updated at Posted at 2024-12-16

はじめに

ここでは、ESMバインディングを使用しているAssemblyScript側のコードから、ホスト側の関数をコールバックする方法を示します。

ESMバインディングの設定方法については、別記事「vite-react-comlink-worker-assemblyscript-webgpu-boilerplateを作った」の「設定項目の抜粋」のセクション内容を参照してください。

※別記事「vite-react-comlink-worker-assemblyscript-webgpu-boilerplateを作った」が、関連して開発したコードからの引用を含めて、3万字弱もの分量があるため、特に有用と思われる部分をこちらの記事に切り出しました。

AssemblyScript側のコード

AssemblyScript側のコードとして、次のようなものを書きます。

AssemblyScript側のコード

export function doSomething(value: u32): void{
  myCallback(value * 1);
  myCallback(value * 2);
  myCallback(value * 3);
}


// @ts-ignore: decorator
@external("env", "myCallback")
export declare function myCallback(value: u32): void;

ここでは、doSomethingという関数が実装されています。
渡された値を、1倍、2倍、3倍した値にして、myCallback関数を計3回呼ぶという内容です。

doSomething関数には、exportがついています。これは、この関数が、AssemblyScript側からホスト側に公開されるものであることを示します。

なお、ここで使われているmyCallback関数は、実際には、AssemblyScriptで実装されるのではなく、ホスト側(WebWorker側)で実装されるものになります。

上のコードの最後の2行が、このことを、@externalアノテーションを用いて設定する部分です。

  「このAssemblyScriptのモジュールにおいて `myCallback`関数を呼び出すときには、その実体として、
    `"env"`というモジュール名前空間の、`myCallback`関数を呼んでね!」

という意味の宣言になっています。
ちなみに、ここでの"env"というのは、AssemblyScriptにおける特別なモジュール名前空間の名称で、ようするにglobalThisのことを指しています(環境変数などのことではありません)。

なお、The AssemblyScript BookのHost bindingsのUsing ESM bindingsのページには、
@external("./otherfile.js", "myFunction")というような表記で、任意のJSファイル内の関数を設定できるように書いてあるのですが、私が試した限りでは、うまく設定できませんでした。

現時点では、node_modules/assemblyscript/std/assembly.jsonでチェックされる内容は、実際のAssemblyScriptのコンパイラで指定できる文法よりも古いため、@externalなどのデコレーターが正しく認識されずに「TS1206: Decorators are not valid here.」のエラーが表示されてしまいます。そうした場合には、上の例のように、下から3行目に「// @ts-ignore: decorator」をつけて、エラーの出力を抑制しておきましょう。

ホスト側のコード

ホスト側では、まず、AssemblyScriptのコンパイラascで作成されたwasmファイルをimportで読み込みます。これをwasmという名前で参照することとしています(importするパスは、あなたの開発している環境でのwasmファイルのビルド先に合わせて修正してください)。

次に、グローバル変数globalThisに、myCallbackという名前で、今回コールバックしてほしい関数を紐づけしておきします。

そのあと、wasmに対して、関数doSomethingを実行します。このdoSomethingがAssemblyScript側の関数として実行される中で、ホスト側のmyCallbackがコールバックされることになります。

ホスト側のコード
import * as wasm from "../../../build/callbackExample/assets";

(globalThis as any).myCallback = function(
  value: number,
): void {
  console.log(`callback: ${value}`);
};
  
wasm.doSomething(123);

実行結果

実行すると、次のような出力が得られるはずです。

callback: 123
callback: 246
callback: 369

まとめ

ホスト側からのWebAssembly側の関数を呼び出して、その結果を1回だけ受け取るのであれば、関数の返値で受け取れば良いのですが、結果を非同期的に複数回にわたって受け取りたい場合には、コールバック関数を用いることが必要になります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?