Skip to content

Commit bbc46f9

Browse files
committed
Fix web-sys Location test
1 parent e66d01f commit bbc46f9

File tree

2 files changed

+52
-13
lines changed

2 files changed

+52
-13
lines changed

crates/web-sys/src/lib.rs

Lines changed: 38 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,48 @@ use js_sys::Object;
1919

2020
#[cfg(feature = "Window")]
2121
pub fn window() -> Option<Window> {
22+
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
2223
use wasm_bindgen::{JsValue, JsCast};
2324

24-
js_sys::Function::new_no_args("return this")
25+
// Cached `Box<JsValue>`, if we've already executed this.
26+
//
27+
// 0 = not calculated
28+
// 1 = `None`
29+
// n = Some(n) == Some(Box<JsValue>)
30+
static WINDOW: AtomicUsize = ATOMIC_USIZE_INIT;
31+
32+
match WINDOW.load(SeqCst) {
33+
0 => {}
34+
1 => return None,
35+
n => return unsafe { Some((*(n as *const JsValue)).clone().unchecked_into()) },
36+
}
37+
38+
// Ok we don't have a cached value, let's load one! Manufacture a function
39+
// to get access to the `this` context and see if it's an instance of
40+
// `Window`.
41+
//
42+
// Note that we avoid `unwrap()` on `call0` to avoid code size bloat, we
43+
// just handle the `Err` case as returning `None`.
44+
let window = js_sys::Function::new_no_args("return this")
2545
.call0(&JsValue::undefined())
26-
.ok()?
27-
.dyn_into::<Window>()
2846
.ok()
47+
.and_then(|w| w.dyn_into::<Window>().ok());
48+
49+
match &window {
50+
None => WINDOW.store(1, SeqCst),
51+
Some(window) => {
52+
let window: &JsValue = window.as_ref();
53+
let ptr: *mut JsValue = Box::into_raw(Box::new(window.clone()));
54+
match WINDOW.compare_exchange(0, ptr as usize, SeqCst, SeqCst) {
55+
// We stored out value, relinquishing ownership of `ptr`
56+
Ok(_) => {}
57+
// Another thread one, drop our value
58+
Err(_) => unsafe { drop(Box::from_raw(ptr)) },
59+
}
60+
}
61+
}
62+
63+
window
2964
}
3065

3166
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));

crates/web-sys/tests/wasm/location.rs

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,60 @@
11
use wasm_bindgen_test::*;
2-
use web_sys::Window;
2+
use web_sys::{self, Location};
3+
4+
fn location() -> Location {
5+
web_sys::window().unwrap().location()
6+
}
37

48
#[wasm_bindgen_test]
59
fn href() {
6-
let loc = Window::location();
10+
let loc = location();
711
loc.href().unwrap();
812
}
913

1014
#[wasm_bindgen_test]
1115
fn origin() {
12-
let loc = Window::location();
16+
let loc = location();
1317
loc.origin().unwrap();
1418
}
1519

1620
#[wasm_bindgen_test]
1721
fn protocol() {
18-
let loc = Window::location();
22+
let loc = location();
1923
loc.protocol().unwrap();
2024
}
2125

2226
#[wasm_bindgen_test]
2327
fn host() {
24-
let loc = Window::location();
28+
let loc = location();
2529
loc.host().unwrap();
2630
}
2731

2832
#[wasm_bindgen_test]
2933
fn hostname() {
30-
let loc = Window::location();
34+
let loc = location();
3135
loc.hostname().unwrap();
3236
}
3337

3438
#[wasm_bindgen_test]
3539
fn port() {
36-
let loc = Window::location();
40+
let loc = location();
3741
loc.port().unwrap();
3842
}
3943

4044
#[wasm_bindgen_test]
4145
fn pathname() {
42-
let loc = Window::location();
46+
let loc = location();
4347
loc.pathname().unwrap();
4448
}
4549

4650
#[wasm_bindgen_test]
4751
fn search() {
48-
let loc = Window::location();
52+
let loc = location();
4953
loc.search().unwrap();
5054
}
5155

5256
#[wasm_bindgen_test]
5357
fn hash() {
54-
let loc = Window::location();
58+
let loc = location();
5559
loc.hash().unwrap();
5660
}

0 commit comments

Comments
 (0)