Fix web-sys Location test

This commit is contained in:
Alex Crichton
2018-09-17 17:39:20 -07:00
parent e66d01f7fb
commit bbc46f92c6
2 changed files with 52 additions and 13 deletions

View File

@ -19,13 +19,48 @@ 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};
js_sys::Function::new_no_args("return this")
// 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()?
.dyn_into::<Window>()
.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
}
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));