開発ツールに頼らず 様々な言語から WebAssembly（第３回）

WebAssembly は多くのプログラム言語からライブラリの様に呼び出す事が出来る。
WebAssembly のコードを書く方法は多くの記事で書かれているが、その使い方はフレームワーク等のツールに頼っている事が多い様だ。
本記事では、そのような便利ツールに出来るだけ頼らず JavaScript, Rust, Python, Ruby から WebAssembly を実行する方法を記載する。

WebAssembly は新しい技術である。
目先の最先端ツールに飛びつくのもよいが、その基礎を学んで長く使える知識を身に着けないか？

本記事はシリーズの第３回である。シリーズ記事の一覧は [第１回] の  **#シリーズ記事一覧** に載せている。シリーズの記事を追加する時は [第１回] の一覧を更新して通知を行うので興味の有る人は [第１回] をストックして欲しい。

# 本記事の概要と過去記事の復習

過去記事では関数を定義した WebAssembly を外部プログラムから実行した。
しかし WebAssembly のコードクラスの様な物であり、外部プログラムでインスタンス化してから実行される。
今回は各インスタンス事に状態（プロパティ、インスタンス変数）を持たせたい。

本記事では `age` という `i64` （符号付 64 bit 整数）のグローバル変数を持つ WebAssembly のコードを作成する。（WebAssembly の **グローバル変数** とは「インスタンス内でグローバルな変数」という意味であり、実質的にはプロパティやインスタンス変数と呼ばれる物に相当する。）

イメージとしては下記の JavaScript のクラスの様な物を作る。

```javascript
class Person {
    constructor() {
        this.age = -1;
    }

    get_age() {
        return this.age;
    }

    set_age(age) {
        this.age = age;
    }
}
```

本当は `name` というプロパティも加えたいのだが、WebAssembly で String 相当の物を扱うのは少し面倒だ。本記事では整数値の `age` だけを扱い、次回以降で `name` というプロパティを加えてみる。

その上で以下の様にに外部プログラムから作成した WebAssembly のコードを実行する。

- Vanilla JS （フレームワークやライブラリを使わない、そのままの JavaScript）から WebAssembly を実行
- Rust, Python, Ruby から低レイヤーのライブラリ [wasmtime] だけを使って WebAssembly を実行

なお、説明の都合上 [Vanilla JS から実行](#vanilla-js-から実行) の章は JavaScript に興味が無くとも読んでほしい。
（そんなに難しい事はやっていないので JavaScript を知らなくとも本質的な部分は理解できるはずだ。）
それ以外の興味の無い言語の章については読み飛ばして問題無い。

本記事の最後に [ポエム](#ポエム) を書いた。
筆者としては読んでくれると嬉しい。

# WebAssembly コードの準備

過去記事同様、WebAssembly Text Format で動作確認をする WebAssembly のコードを作成し、wat2wasm でコンパイルする。

## wabt のインストール

[github](https://github.com/WebAssembly/wabt) の README.md を読んでコンパイルする。
C++ のコンパイル環境が必要なので注意。

wat2wasm というコマンドがコンパイルされるので、必要に応じて Path を通しておくと良いだろう。

## wasm ファイルの準備

wasm ファイルとは、WebAssembly の規格に沿ったバイナリファイルの事である。
最初に各種言語から動かして動作確認するための wasm ファイルを用意しよう。

テキストエディタで以下の様な内容のファイルを作成し、 **/tmp/person.wat** という名前で保存する。

```wat
(module
    (global $inner_age (export "age") (mut i64) (i64.const -1))

    (func (export "get_age") (result i64)
        global.get $inner_age)

    (func (export "set_age") (param $age i64)
        local.get $age
        global.set $inner_age))
```

上記は WebAssembly Text Format という wasm ファイルのソースコードだ。
多くの読者に内容を何となく理解してもらうには、これが良いと思って選択した。

上記コードは大まかに以下の事を行っている。
（以下で `i64` とは「符号付 64 bit 整数」の事である。）

- 変更可能な `i64` 型のグローバル変数（インスタンス変数）を定義。この変数を `age` という名前で外部からアクセス可能にし、この wasm ファイル内部から `$inner_age` という名前でアクセス可能にしている。（外部と内部で名前を変更した理由は、説明上分かりやすくするためである。普通は同じにするだろう。）
- 関数を定義。この関数を `get_age` という名前で外部からアクセス可能にしている。（内部からアクセスするための名前は付けていない。ただし内部からアクセスするための抜け道は存在する。）この関数は引数を取らず、 `i64` 1 個を返す。
- 関数を定義。この関数を `set_age` という名前で外部からアクセス可能にしている。（内部からアクセスするための名前は付けていない。ただし内部からアクセスするための抜け道は存在する。）この関数は `i64` 引数を 1 個とり、戻り値は無い。

名前から理解できると思うが、 `get_age`, `set_age` はそれぞれ「ゲッター」、「セッター」と呼ばれる関数である。

プロパティの値へ直接アクセスする事を許すべきか、セッターやゲッターと呼ばれる関数を介して行うべきかは議論の余地が有る。今回は説明の為に両方可能にした。
値への直接アクセスを許さないならば `(export "age")` という部分を削除すればよいし、セッターやゲッターを使いたく無ければ該当する関数を削除してかまわない。

この wat ファイルを以下の様に wat2wasm コマンドでコンパイルすると **/tmp/person.wasm** というバイナリファイルが出来る。

```sh
$ wat2wasm -o /tmp/import.wasm /tmp/person.wat
$ ls /tmp/person.wasm
/tmp/person.wasm
```

# Vanilla JS から実行

説明の都合上、本章は JavaScript に興味の無い人でも斜めに読んで欲しい。

## 筆者の JavaScript 環境

- nodejs v18.16.1

## Vanilla JS のコード

nodejs から WebAssembly を実行するコードは、例えば下記の様になる。

```javascript
// Build module
const fs = require('fs');
const wasm = fs.readFileSync('/tmp/person.wasm');
const mod = new WebAssembly.Module(wasm);

// Build Instances
const importObject = {};
const person1 = new WebAssembly.Instance(mod, importObject);
const person2 = new WebAssembly.Instance(mod, importObject);

// Set and get the age of person1 via the functions.
person1.exports.set_age(BigInt(37));
console.log(`The age of "person1" is ${person1.exports.get_age()}.`);

// Set and get the age of person2 via the global variable.
person2.exports.age.value = BigInt(24);
console.log(`The age of "person2" is ${person2.exports.age.value}.`);
```

上記のファイルを `call_wasm.js` という名前で保存し実行すると、下記の様な結果を得る。

```sh
node call_wasm.js
The age of "person1" is 37.
The age of "person2" is 24.
```

JavaScript のコードを少しずつ読んでみる。
（以下の **太字リンク** は JavaScript のクラス名（コンストラクター名）である事を示す。リンク先は [MDN Web Docs](https://developer.mozilla.org/en-US/) 。）

最初に以下を読んでみる。

```javascript
// Build module
const fs = require('fs');
const wasm = fs.readFileSync('/tmp/person.wasm');
const mod = new WebAssembly.Module(wasm);

// Build Instances
const importObject = {};
const person1 = new WebAssembly.Instance(mod, importObject);
const person2 = new WebAssembly.Instance(mod, importObject);
```

ここまでは [第１回] とほとんど同じだ。
違いは wasm ファイルのパスと、インスタンスを 2 個作っている事だけだ。

次に以下の行を読んでみる。

```javascript
// Set and get the age of person1 via the functions.
person1.exports.set_age(BigInt(37));
console.log(`The age of "person1" is ${person1.exports.get_age()}.`);
```

ここでも [第１回] と同様の方法でインスタンスのメソッドを実行している。
WebAssembly の `i64` は JavaScript の `BigInt` に相当するので注意しよう。

続いて以下の行を読んでみる。

```javascript
// Set and get the age of person2 via the global variable.
person2.exports.age.value = BigInt(24);
console.log(`The age of "person2" is ${person2.exports.age.value}.`);
```

ここは過去の記事とは少し違う。
公開された（public な）変数 `age` にアクセスしているのだが、外部プログラムである JavaScript 上で `age` は `i64` （つまり `BigInt` ）では無く **[Global][Global_js]** だ。
実際の値は `age.value` でアクセスする必要がある。

過去記事でも書いたが、WebAssembly は静的型付け言語である。
`person1`, `person2` いずれの場合においても `age` に `BigInt` 以外の値を設定しようとすると `TypeError` が投げられるだろう。

# wasmtime から実行

以降の章では wasmtime を使って [Rust から実行](#rust-から実行), [Python から実行](#python-から実行), [Ruby から実行](#ruby-から実行) 方法について、それぞれ説明している。
不要な章は読み飛ばしても大丈夫だ。

## Rust から実行

### 筆者の Rust 環境

- cargo 1.70.0
- rustup 1.26.0
- rustc 1.70.0 stable-x86_64-unknown-linux-gnu

### Rust のコード

下記の様に call_person というプロジェクトを作成する。

```sh
$ cargo new call_person
$ cd call_person
```

Cargo.toml の `[dependencies]` セクションに wasmtime をの設定を加える。
筆者の環境では Cargo.toml は下記の様になった。

```toml
[package]
name = "call_person"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
wasmtime = "10.0.1"
```

Rust から WebAssembly を実行するコードは、例えば下記の様になる。

```rust
use std::fs;
use wasmtime::*;

fn main() -> wasmtime::Result<()> {
    // Build `Engine`.
    let engine = Engine::default();

    // Build `Module`.
    let wasm = fs::read("/tmp/person.wasm").unwrap();
    let module = Module::new(&engine, wasm)?;

    // Build `Store`.
    let mut store = Store::new(&engine, ());

    // Build `Instance`
    let person1 = Instance::new(&mut store, &module, &[])?;
    let person2 = Instance::new(&mut store, &module, &[])?;

    // Set and get the age of person1 via the method.
    {
        let get_age = person1.get_typed_func::<(), i64>(&mut store, "get_age")?;
        let set_age = person1.get_typed_func::<i64, ()>(&mut store, "set_age")?;
        set_age.call(&mut store, 37)?;
        println!(
            r#"The age of "person1" is {}."#,
            &(get_age.call(&mut store, ())?)
        )
    }

    // Set and get the age of person2 via the global variable.
    {
        let age = person2.get_global(&mut store, "age").unwrap();
        age.set(&mut store, Val::I64(24))?;
        println!(
            r#"The age of "person2" is {}."#,
            &(age.get(&mut store).unwrap_i64())
        );
    }

    Ok(())
}
```

上記の内容で `src/main.rs` を上書きして実行すると、下記の様な結果を得る。

```sh
$ cargo run
    Finished dev [unoptimized + debuginfo] target(s) in 0.04s
     Running `target/debug/call_person`
The age of "person1" is 37.
The age of "person2" is 24.
```

上記の Rust コードを少しずつ解説していく。
以下で **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Rust 版 wasmtime の公式ドキュメント](https://docs.rs/wasmtime/10.0.1/wasmtime/index.html) 。

まずはコードの全体像を把握しよう。

```rust
use std::fs;
use wasmtime::*;

fn main() -> wasmtime::Result<()> {
...
}
```

見ての通り、本コードは main 関数が定義してあるだけである。

以下、main 関数の中身を上から少しずつ読んでみる
まずは以下の行からだ。

```rust
    // Build `Engine`.
    let engine = Engine::default();

    // Build `Module`.
    let wasm = fs::read("/tmp/person.wasm").unwrap();
    let module = Module::new(&engine, wasm)?;

    // Build `Store`.
    let mut store = Store::new(&engine, ());
```

上記は [第１回] と全く同じコードなので説明を省略する。

続いて以下の行だ。

```rust
    // Build `Instance`
    let person1 = Instance::new(&mut store, &module, &[])?;
    let person2 = Instance::new(&mut store, &module, &[])?;
```

ここでも [第１回] と同じような方法で **[Instance][Instance_rust]** を 2 個作成している。

普段から Rust のコードを書いている人は、変数の宣言時に `let mut person1` の様に `mut` が付かない事に違和感を覚えるかもしれない。
筆者も最初は「これでは `age` の値を変更できないのではないか？」と思った。

しかし、実際にはこのコードで問題ない。

Rust 上で `age` の型は **[Global][Global_rust]** となっている。
そして `person1` や `person2` は、それぞれの `age` の値を保持する **[Global][Global_rust]** への参照しか持っていない。

`person1` の `age` を変更すると、その値を保持する **[Global][Global_rust]** は変更される。しかし `person1` 内部の参照先のアドレスは変わらない。
なので `person1` や `person2` に `mut` を付ける必要は無い。

では `person1` や `person2` から参照される **[Global][Global_rust]** の実態はどこにあるのか？
それは **[Store][Store_rust]** が持っている。
この後解説するが、 `age` の値を変更する際に `&mut store` という参照を関数に渡している。

**[Store][Store_rust]** の実装を見ると、初期化を遅延している事が多い。
直感的には「この処理は更新しないだろう」と思うような場面でも実際には更新される可能性が有る。
**[Instance][Instance_rust]** の使用時には、だいたい `&mut store` を引数に取る関数を実行する。

ところで `let person2 = person1.clone();` の様な書き方をすると、 `person1` と `person2` は同じ **[Global][Global_rust]** を参照してしまう。（ `person2` は `person1` の浅いコピーになってしまう。）

`person1` と `person2` の `age` が一度に変更されると困るので、ちゃんと `person2` も `Instance::new` を使って初期化しよう。

続いて以下の行を読んでみる。

```rust
    // Set and get the age of person1 via the method.
    {
        let get_age = person1.get_typed_func::<(), i64>(&mut store, "get_age")?;
        let set_age = person1.get_typed_func::<i64, ()>(&mut store, "set_age")?;
        set_age.call(&mut store, 37)?;
        println!(
            r#"The age of "person1" is {}."#,
            &(get_age.call(&mut store, ())?)
        )
    }
```

ここでは [第１回] と同じような方法で `person1` の `age` を関数 `get_age`, `set_age` を使って読み書きしている。
特筆すべき点は無いだろう。

続いて以下の行を読んでみる。

```rust
    // Set and get the age of person2 via the global variable.
    {
        let age = person2.get_global(&mut store, "age").unwrap();
        age.set(&mut store, Val::I64(24))?;
        println!(
            r#"The age of "person2" is {}."#,
            &(age.get(&mut store).unwrap_i64())
        );
    }
```

ここでは `person2` の `age` をグローバル変数を介して読み書きしている。
`person2.get_global(&mut store, "age")` は **[Global][Global_rust]** の `Option` を返す。
（ `age` という **[Global][Global_rust]** を wasm ファイルが export していない場合、 `None` を返す。）

**[Global][Global_rust]** は **[Val][Val_rust]** という enum のラッパーの様な構造をしている。
実際に値を読み書きする際は `set` や `get` といったメソッドを介する必要が有るので注意しよう。

個人的には関数の場合は `get_typed_func` で型を指定して取得できたのだからグローバル変数も `get_typed_global` で型を指定して取得できれば良いと思うのだが、違うようだ。

## Python から実行

### 筆者の Python 環境

- Python 3.11.2
- pip 23.0.1

### Python のコード

最初に Python の version と環境に応じた方法で wasmtime をインストールする。

```sh
$ pip install wasmtime
Collecting wasmtime
  Downloading wasmtime-9.0.0-py3-none-manylinux1_x86_64.whl (6.6 MB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 6.6/6.6 MB 2.1 MB/s eta 0:00:00
Installing collected packages: wasmtime
Successfully installed wasmtime-9.0.0
```

Python から WebAssembly を実行するコードは、例えば下記の様になる。

```python
from wasmtime import Engine, Module, Store, Instance

# Build Engine
engine = Engine()

# Build Module
wasm = open('/tmp/person.wasm', 'rb').read()
module = Module(engine, wasm)

# Build Store
store = Store(engine)

# Build Instance
person1 = Instance(store, module, ())
person2 = Instance(store, module, ())

# Set and get the age of person1 via the method.
person1.exports(store)['set_age'](store, 37)
print("""The age of "person1" is %d.""" % person1.exports(store)['get_age'](store))

# Set and get the age of person2 via the global variable.
person2.exports(store)['age'].set_value(store, 24)
print("""The age of "person2" is %d.""" % person2.exports(store)['age'].value(store))
```

上記の内容を call_wasm.py というファイル名で保存すると、実行結果は以下の様になる。

```sh
$ python call_wasm.py
The age of "person1" is 37.
The age of "person2" is 24.
```

上記の Python コードを少しずつ解説していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Python 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-py/) である。

最初に少しまとめて読んでみよう。

```python
from wasmtime import Engine, Module, Store, Instance

# Build Engine
engine = Engine()

# Build Module
wasm = open('/tmp/person.wasm', 'rb').read()
module = Module(engine, wasm)

# Build Store
store = Store(engine)

# Build Instance
person1 = Instance(store, module, ())
person2 = Instance(store, module, ())
```

ここまでは [第１回] とほとんど同じだ。
違いは wasm ファイルのパスと、インスタンスを 2 個作っている事だけだ。

続いて以下の行を読んでみる。

```python
# Set and get the age of person1 via the method.
person1.exports(store)['set_age'](store, 37)
print("""The age of "person1" is %d.""" % person1.exports(store)['get_age'](store))
```

ここでは [第１回] と同じような方法で `person1` の `age` を関数 `get_age`, `set_age` を使って読み書きしている。
特筆すべき点は無いだろう。

続いて以下の行を読んでみる。

```python
# Set and get the age of person2 via the global variable.
person2.exports(store)['age'].set_value(store, 24)
print("""The age of "person2" is %d.""" % person2.exports(store)['age'].value(store))
```

ここは過去の記事とは少し違う。
公開された（public な）変数 `age` にアクセスしているのだが、外部プログラムである Python 上で `age` は `i64` （つまり `int` ）では無く **[Global][Global_py]** だ。
実際の値には `set_value()` や `value()` と言ったメソッドを介してアクセスする。

過去記事でも書いたが、WebAssembly は静的型付け言語である。
`person1`, `person2` いずれの場合においても `age` に `int` 以外の値を設定しようとすると `TypeError` が投げられるだろう。

## Ruby から実行

### 筆者の Ruby 環境

- ruby 3.1.2p20

### Ruby のコード

最初に gem で wasmtime をインストールする。
（必要に応じて bundler 等を使うと良いだろう。）

```sh
$ gem install wasmtime
Fetching wasmtime-9.0.1-x86_64-linux.gem
Successfully installed wasmtime-9.0.1-x86_64-linux
Parsing documentation for wasmtime-9.0.1-x86_64-linux
Installing ri documentation for wasmtime-9.0.1-x86_64-linux
Done installing documentation for wasmtime after 0 seconds
1 gem installed
```

Ruby から WebAssembly を実行するコードは、例えば下記の様になる。

```ruby
require 'wasmtime'

# Build Engine
engine = Wasmtime::Engine.new

# Build Module
wasm = open('/tmp/person.wasm', 'rb').read
mod = Wasmtime::Module.new(engine, wasm)

# Build Store
store = Wasmtime::Store.new(engine)

# Build instance
person1 = Wasmtime::Instance.new(store, mod)
person2 = Wasmtime::Instance.new(store, mod)

# Set and get the age of person1 via the method.
person1.export('set_age').to_func.call(37)
puts(%q!The age of "person1" is %d.! % person1.export('get_age').to_func.call)

# Set and get the age of person2 via the global variable.
person2.export('age').to_global.set(24)
puts(%q!The age of "person2" is %d.! % person2.export('age').to_global.get)
```

上記の内容を call_wasm.rb というファイル名で保存すると、実行結果は以下の様になる。

```sh
$ ruby call_wasm.rb
The age of "person1" is 37.
The age of "person2" is 24.
```

上記の Ruby コードを少しずつ解説していく。
以下では **太字のリンク** は wasmtime で定義されたクラスである事を示す。リンク先は [Ruby 版 wasmtime の公式ドキュメント](https://bytecodealliance.github.io/wasmtime-rb/latest/top-level-namespace.html) である。


最初に少しまとめて読んでみよう。

```ruby
require 'wasmtime'

# Build Engine
engine = Wasmtime::Engine.new

# Build Module
wasm = open('/tmp/person.wasm', 'rb').read
mod = Wasmtime::Module.new(engine, wasm)

# Build Store
store = Wasmtime::Store.new(engine)

# Build instance
person1 = Wasmtime::Instance.new(store, mod)
person2 = Wasmtime::Instance.new(store, mod)
```

ここまでは [第１回] とほとんど同じだ。
違いは wasm ファイルのパスと、インスタンスを 2 個作っている事だけだ。

続いて以下の行を読んでみる。

```ruby
# Set and get the age of person1 via the method.
person1.export('set_age').to_func.call(37)
puts(%q!The age of "person1" is %d.! % person1.export('get_age').to_func.call)
```

ここでは [第１回] と同じような方法で `person1` の `age` を関数 `get_age`, `set_age` を使って読み書きしている。
特筆すべき点は無いだろう。

続いて以下の行を読んでみる。

```ruby
# Set and get the age of person2 via the global variable.
person2.export('age').to_global.set(24)
puts(%q!The age of "person2" is %d.! % person2.export('age').to_global.get)
```

ここは過去の記事とは少し違う。
公開された（public な）変数 `age` にアクセスしているのだが、外部プログラムである Python 上で `age` は `i64` （つまり `Integer` ）では無く **[Global][Global_rb]** だ。
実際の値は `get` や `set` と言ったメソッドを介してアクセスする。

過去記事でも書いたが、WebAssembly は静的型付け言語である。
`person1`, `person2` いずれの場合においても `age` に `Integer` 以外の値を設定しようとすると `TypeError` が投げられるだろう。

# ポエム

本記事で紹介したコードは説明の為に余計な物を極力排除したため、どれもあまり美しくないと思っている。筆者が業務でコードを書く事になったら、もっと工夫するだろう。

中でも Rust のコードは最悪だ。 [Rust から実行](#rust-から実行) を読まれた方は気が付くだろうが、このコードはプログラマーの直感に反する。なぜ Rust のコードだけが他の JavaScript, Python, Ruby に比べて、こんなに汚いのだろうか？
そもそも論として、筆者は wasm ファイルを Rust から扱う事は筋が良くないのではないかと思っている。

少し話が脱線するが、他で実装されたコード（ライブラリやプログラム）を組み合わせる事で自身は単純なロジックしか持たない様な使い方をするプログラム言語を「Glue 言語」と言う事も有る。（Glue とは英語で「糊（のり）」という意味。）

例えば JavaScript の柔軟性は複雑なロジックを実装する事には向かないが、Glue 言語としては有利に働く事が多い。Glue 言語と下回りのコード（今回は WebAssembly）の接合部分のややこしい部分を、JavaScript は「何となく」で動くようにしてくれる。

もちろん「何となく」で動かすためにはコスト（CPU 実行時間やメモリ効率）がかかる。しかし所詮呼び出すだけだ。全体のパフォーマンスに与える影響は限定的になるだろう。

また、静的型付け言語であり内部まで細かい調整が可能な WebAssembly は、JavaScript と対極にある。WebAssembly と JavaScript を両方使う事で、互いの欠点を補う事が出来るだろう。
Ruby や Python も同様だ。

Rust はどうだろう？
Rust は細かい事を気にするので、プログラマーは WebAssembly との接合部分の面倒な事を全て指示する必要が有る。一方で WebAssembly と Rust の得意分野、苦手分野は重複する部分が大きい。それならば初めから全て Rust で書いた方がシンプルでパフォーマンスも良くなるのではないか？

「本当に外部プログラムを Rust で実装する必要有る？」と自分で聞いてみると良いかもしれない。「難しい部分だけ Rust で書き WebAssembly 形式にコンパイルして、Glue 言語には他の言語を選択する」という方法もある。もちろん「外部プログラムを Rust で書くべき」特殊な事例もあるはずだが、多くは無いと思う。「流行だから」という理由だけで WebAssembly を使うのは良くないかもしれない。

[wasmtime]: https://github.com/bytecodealliance/wasmtime
[第１回]: https://qiita.com/wbcchsyn/items/e1f699bb86c466411e36

[Global_js]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Global
[Instance_js]: https://developer.mozilla.org/en-US/docs/WebAssembly/JavaScript_interface/Instance

[Global_rust]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Global.html
[Instance_rust]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Instance.html
[Store_rust]: https://docs.rs/wasmtime/10.0.1/wasmtime/struct.Store.html
[Val_rust]: https://docs.rs/wasmtime/10.0.1/wasmtime/enum.Val.html

[Global_py]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Global
[Instance_py]: https://bytecodealliance.github.io/wasmtime-py/#wasmtime.Instance

[Global_rb]: https://bytecodealliance.github.io/wasmtime-rb/latest/Wasmtime/Global.html