Storing global weak mutable references for web assembly

I am writing a WebGL renderer using wasm_bindgen and it has a function responsible for the main loop:

#[wasm_bindgen]
pub fn render() {
  let f = Rc::new(RefCell:new(None));
  let g = Rc::clone(&f);

  let camera = Camera::new();

  *g.borrow_mut() = Some(Closure::wrap(Box::new(move || {
    // Use the camera
    request_animation_frame(f.borrow().as_ref().unwrap());
  }) as Box<dyn FnMut()>));
  request_animation_frame(g.borrow().as_ref().unwrap());
}

Now I want that camera to be editable from the TypeScript side through something like this:

#[wasm_bindgen]
pub fn move_camera(x: f32, y: f32, z: f32) {
  let mut camera = <???>;

  camera.move_to(x, y, z);
  camera.update();
}

And the issue I'm facing is how to make the camera accessible outside the render function. The call to move_camera will come from outside Rust, so it needs to be accessible globally.

From my research it seems like I need an Arc<RwLock<Camera>> stored inside a struct and then create a static ref to that struct using lazy_ref. But I can't start a RwLock with None and the camera does not exist before the render function gets called.

So what I am looking for is a thread-safe way to store a weak mutable reference to a value that starts empty and can be assigned at runtime.

I think Arc<RwLock<Option<Camera>>> fits the bill...

Perhaps you could use the once_cell crate to create a static OnceCell<RwLock<Camera>>. It can be initialized once, then read from and written to thereafter.

You don't need a global object if you can have an initialization function that returns something.

struct RendererApi {
    state: Rc<RefCell<State>>,
}
struct State {
    camera: Camera,
    // probably other fields eventually...
}

Your initialization function would construct and return a RendererApi, and you would export methods on RendererApi (with &self as receiver) that access the mutable State internally.

once_cell::sync::OnceCell<RwLock<Camera>> is an available option if you do decide that it should be global, instead.

Ah, tunnel vision was the issue.
You are correct, I can have an initializer return a struct exposing a public API and keep the interior mutability on the state only.

Thank you! That solves it.