RustでWebAssembly: MyAppの'static 参照を作る方法

# はじめに
[前回](https://qiita.com/mokemokechicken/items/30d908a26ed103622a15)は、アプリケーション状態のベースとなる `MyApp` を `requestAnimationFrame()` に渡すClosureにキャプチャさせるのでDropされないという構造になっていました。

これとは別に `MyApp` 自体をstaticな変数に置いてしまうという方法も考えられます。安易にstaticを使うというのは大抵アンチパターンな気もしますが、WebBrower上のアプリケーションであれば、まあ動作するアプリケーションは１つであろうし、JSでそういうやり方になっているものも珍しくないでしょう（というか、普通`window`とかに保存することでそうなっている)。
そして、現状の`wasm-bindgen`だとHTTPでのfetchなどの非同期関数を任意のタイミングで実行しようと思うと `wasm_bindgen_futures::spawn_local()` を使うしかないのかなと思いますが、この `spawn_local()` に渡せる async function は `'static` な参照しか使えないことになっています(というより、stackに関連したものを渡せないということらしいですが)。そうなると fetch の結果を `MyAPP` とかに渡したいというときに `&'static MyApp` とかになっているとやりやすいです。

まあ、そういうわけで 「MyAppの`'static`参照を作る方法」について考えてみました。
ちゃんとした複雑なアプリケーションで使ったことはないので、この後どういうTrapがあるかまだわかりませんが、とりあえずは問題なく動作しました。

# MyAppの`'static`参照を作る方法
## 実装方法1: `Rc<RefCell<MyApp>>` を使う

ポイントになるのは、この辺りかなと思います。
`static mut` な変数へのアクセスには `unsafe` で囲む必要があるようです。
毎回 `unsafe` とか使うと心理的に負担なので、簡単なwrapperを用意しておきます。

```rust:lib.rs

static mut MY_APP: Option<Rc<RefCell<MyApp>>> = None;

pub fn init_my_app() {
    unsafe {
        MY_APP = Some(Rc::new(RefCell::new(MyApp::new())));
    }
}

pub fn my_app() -> Ref<'static, MyApp> {
    unsafe { MY_APP.as_ref().unwrap().borrow() }
}

pub fn my_app_mut() -> RefMut<'static, MyApp> {
    unsafe { MY_APP.as_ref().unwrap().borrow_mut() }
}
```

上記は、本来できないような下記のコードがコンパイルを通ってしまいますが、実行時に panic になります。なので、使う時には普段より一層の注意が必要になります。

```rust
    let mut x = my_app_mut();
    let y = my_app();
```

## 実装方法2: `Box<MyApp>` を使う
こういう形でも動くようです。

```rust

static mut MY_APP: Option<Box<MyApp>> = None;

pub fn init_my_app() {
    unsafe {
        MY_APP = Some(Box::new(MyApp::new()));
    }
}

pub fn my_app() -> &'static MyApp {
    unsafe { MY_APP.as_ref().unwrap() }
}

pub fn my_app_mut() -> &'static mut MyApp {
    unsafe { MY_APP.as_mut().unwrap() }
}
```

これのポイントは以下のようなRust的掟破りのコードがコンパイルも実行時も通ることです。
WebBrowserのゆるいアプリケーションの場合、だいたいこれくらいゆるさで良い気もするし、これは意外と使えるかもしれない。

```rust
    let mut x = my_app_mut();
    x.clicks += 1;
    let y = my_app();
    log!("clicks={}", y.clicks);
```

## 使い方

これらは以下のように使うことができます。
ポイントは `pub async fn my_async_process(param: u32)` みたいな MyAppへの参照をもたせられない関数の中でもアクセスできることです。
まあ、JSやwasm内では単一Threadなので、MyAppを使ってすぐにしまっておけば大抵は問題にならないとは思うのですが。

```rust:lib.rs
#[wasm_bindgen]
pub fn start() {
    console_error_panic_hook::set_once();
    log!("start");
    init_my_app();
    let closure_captured = Rc::new(RefCell::new(None));
    let closure_cloned = Rc::clone(&closure_captured);

    // setup requestAnimationFrame Loop
    {
        closure_cloned.replace(Some(Closure::wrap(Box::new(move |time: f64| {
            my_app_mut().on_animation_frame(time);
            request_animation_frame(closure_captured.borrow().as_ref().unwrap());
        }) as Box<dyn FnMut(f64)>)));
        request_animation_frame(closure_cloned.borrow().as_ref().unwrap());
    }

    // setup onClick
    {
        let c = Closure::wrap(Box::new(move |e| {
            my_app_mut().on_click(e);
        }) as Box<dyn FnMut(JsValue)>);
        document()
            .add_event_listener_with_callback("click", c.as_ref().unchecked_ref())
            .unwrap();
        c.forget(); // c を Rustのメモリ管理から外して JSのGCにわたす
    }
}

impl MyApp {
    pub fn on_click(&mut self, event: JsValue) {
        self.clicks += 1;
        spawn_local(my_async_process(self.clicks));
    }
}

pub async fn my_async_process(param: u32) {
    // 何か await とかしたりできる(fetchとか)
    // spawn_local() で使えるのは static な 参照しかないが、 my_app_mut() はそれを満たしている。
    my_app_mut().async_count += param;
}

```

# さいごに
[コード全体はこちら](https://github.com/mokemokechicken/rust_wasm_example/tree/master/example6)です。
こういうのはパンドラの箱感がありますね。