Add js_sys::global

This commit is contained in:
Alex Crichton
2018-09-18 15:34:40 -07:00
parent 604ecd9529
commit a83d561bb3
3 changed files with 62 additions and 87 deletions

View File

@ -15,52 +15,14 @@
extern crate wasm_bindgen;
extern crate js_sys;
use js_sys::Object;
#[cfg(feature = "Window")]
pub fn window() -> Option<Window> {
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
use wasm_bindgen::{JsValue, JsCast};
use wasm_bindgen::JsCast;
// Cached `Box<JsValue>`, if we've already executed this.
//
// 0 = not calculated
// 1 = `None`
// n = Some(n) == Some(Box<JsValue>)
static WINDOW: AtomicUsize = ATOMIC_USIZE_INIT;
match WINDOW.load(SeqCst) {
0 => {}
1 => return None,
n => return unsafe { Some((*(n as *const JsValue)).clone().unchecked_into()) },
}
// Ok we don't have a cached value, let's load one! Manufacture a function
// to get access to the `this` context and see if it's an instance of
// `Window`.
//
// Note that we avoid `unwrap()` on `call0` to avoid code size bloat, we
// just handle the `Err` case as returning `None`.
let window = js_sys::Function::new_no_args("return this")
.call0(&JsValue::undefined())
.ok()
.and_then(|w| w.dyn_into::<Window>().ok());
match &window {
None => WINDOW.store(1, SeqCst),
Some(window) => {
let window: &JsValue = window.as_ref();
let ptr: *mut JsValue = Box::into_raw(Box::new(window.clone()));
match WINDOW.compare_exchange(0, ptr as usize, SeqCst, SeqCst) {
// We stored out value, relinquishing ownership of `ptr`
Ok(_) => {}
// Another thread one, drop our value
Err(_) => unsafe { drop(Box::from_raw(ptr)) },
}
}
}
window
js_sys::global().dyn_into::<Window>().ok()
}
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));