Skip to content

Commit 5832ff3

Browse files
authored
Merge pull request #847 from alexcrichton/fix-window
Move all methods on `Window` back to methods
2 parents 300aca3 + a83d561 commit 5832ff3

File tree

23 files changed

+157
-148
lines changed

23 files changed

+157
-148
lines changed

crates/backend/src/ast.rs

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ pub enum ImportFunctionKind {
9898
ty: syn::Type,
9999
kind: MethodKind,
100100
},
101-
ScopedMethod {
102-
ty: syn::Type,
103-
operation: Operation,
104-
},
105101
Normal,
106102
}
107103

@@ -432,16 +428,10 @@ impl ImportFunction {
432428
}
433429
};
434430
Some(shared::MethodData {
435-
class: Some(class.clone()),
431+
class: class.clone(),
436432
kind,
437433
})
438434
}
439-
ImportFunctionKind::ScopedMethod { ref operation, .. } => {
440-
Some(shared::MethodData {
441-
class: None,
442-
kind: shared::MethodKind::Operation(shared_operation(operation)),
443-
})
444-
}
445435
ImportFunctionKind::Normal => None,
446436
};
447437

crates/backend/src/codegen.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -772,9 +772,6 @@ impl TryToTokens for ast::ImportFunction {
772772
}
773773
class_ty = Some(ty);
774774
}
775-
ast::ImportFunctionKind::ScopedMethod { ref ty, .. } => {
776-
class_ty = Some(ty);
777-
}
778775
ast::ImportFunctionKind::Normal => {}
779776
}
780777
let vis = &self.function.rust_vis;

crates/backend/src/defined.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,6 @@ impl ImportedTypes for ast::ImportFunctionKind {
256256
{
257257
match self {
258258
ast::ImportFunctionKind::Method { ty, .. } => ty.imported_types(f),
259-
ast::ImportFunctionKind::ScopedMethod { ty, .. } => ty.imported_types(f),
260259
ast::ImportFunctionKind::Normal => {}
261260
}
262261
}

crates/cli-support/src/js/mod.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,30 +2008,7 @@ impl<'a, 'b> SubContext<'a, 'b> {
20082008
}
20092009
};
20102010

2011-
let class = match &method_data.class {
2012-
Some(class) => self.import_name(info, class)?,
2013-
None => {
2014-
let op = match &method_data.kind {
2015-
shared::MethodKind::Operation(op) => op,
2016-
shared::MethodKind::Constructor => {
2017-
bail!("\"no class\" methods cannot be constructors")
2018-
}
2019-
};
2020-
match &op.kind {
2021-
shared::OperationKind::Regular => {
2022-
return Ok(import.function.name.to_string())
2023-
}
2024-
shared::OperationKind::Getter(g) => {
2025-
return Ok(format!("(() => {})", g));
2026-
}
2027-
shared::OperationKind::Setter(g) => {
2028-
return Ok(format!("(v => {} = v)", g));
2029-
}
2030-
_ => bail!("\"no class\" methods must be regular/getter/setter"),
2031-
}
2032-
2033-
}
2034-
};
2011+
let class = self.import_name(info, &method_data.class)?;
20352012
let op = match &method_data.kind {
20362013
shared::MethodKind::Constructor => return Ok(format!("new {}", class)),
20372014
shared::MethodKind::Operation(op) => op,

crates/js-sys/src/lib.rs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ extern crate wasm_bindgen;
2323
use std::mem;
2424
use std::fmt;
2525

26+
use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering::SeqCst};
27+
use wasm_bindgen::JsCast;
2628
use wasm_bindgen::prelude::*;
2729

2830
// When adding new imports:
@@ -4100,3 +4102,54 @@ extern {
41004102
#[wasm_bindgen(method)]
41014103
pub fn finally(this: &Promise, cb: &Closure<FnMut()>) -> Promise;
41024104
}
4105+
4106+
/// Returns a handle to the global scope object.
4107+
///
4108+
/// This allows access to the global properties and global names by accessing
4109+
/// the `Object` returned.
4110+
pub fn global() -> Object {
4111+
// Cached `Box<JsValue>`, if we've already executed this.
4112+
//
4113+
// 0 = not calculated
4114+
// n = Some(n) == Some(Box<JsValue>)
4115+
static GLOBAL: AtomicUsize = ATOMIC_USIZE_INIT;
4116+
4117+
match GLOBAL.load(SeqCst) {
4118+
0 => {}
4119+
n => return unsafe { (*(n as *const JsValue)).clone().unchecked_into() },
4120+
}
4121+
4122+
// Ok we don't have a cached value, let's load one!
4123+
//
4124+
// According to StackOverflow you can access the global object via:
4125+
//
4126+
// const global = Function('return this')();
4127+
//
4128+
// I think that's because the manufactured function isn't in "strict" mode.
4129+
// It also turns out that non-strict functions will ignore `undefined`
4130+
// values for `this` when using the `apply` function.
4131+
//
4132+
// As a result we use the equivalent of this snippet to get a handle to the
4133+
// global object in a sort of roundabout way that should hopefully work in
4134+
// all contexts like ESM, node, browsers, etc.
4135+
let this = Function::new_no_args("return this")
4136+
.call0(&JsValue::undefined())
4137+
.ok();
4138+
4139+
// Note that we avoid `unwrap()` on `call0` to avoid code size bloat, we
4140+
// just handle the `Err` case as returning a different object.
4141+
debug_assert!(this.is_some());
4142+
let this = match this {
4143+
Some(this) => this,
4144+
None => return JsValue::undefined().unchecked_into(),
4145+
};
4146+
4147+
let ptr: *mut JsValue = Box::into_raw(Box::new(this.clone()));
4148+
match GLOBAL.compare_exchange(0, ptr as usize, SeqCst, SeqCst) {
4149+
// We stored out value, relinquishing ownership of `ptr`
4150+
Ok(_) => {}
4151+
// Another thread one, drop our value
4152+
Err(_) => unsafe { drop(Box::from_raw(ptr)) },
4153+
}
4154+
this.unchecked_into()
4155+
}

crates/macro-support/src/parser.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -510,7 +510,6 @@ impl<'a> ConvertToAst<(BindgenAttrs, &'a Option<String>)> for syn::ForeignItemFn
510510

511511
let shim = {
512512
let ns = match kind {
513-
ast::ImportFunctionKind::ScopedMethod { .. } |
514513
ast::ImportFunctionKind::Normal => (0, "n"),
515514
ast::ImportFunctionKind::Method { ref class, .. } => (1, &class[..]),
516515
};

crates/shared/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ pub struct ImportFunction {
5151

5252
#[derive(Deserialize, Serialize)]
5353
pub struct MethodData {
54-
pub class: Option<String>,
54+
pub class: String,
5555
pub kind: MethodKind,
5656
}
5757

crates/test/src/rt/detect.rs

Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! Runtime detection of whether we're in node.js or a browser.
22
33
use wasm_bindgen::prelude::*;
4-
use js_sys::Function;
4+
use wasm_bindgen::JsCast;
5+
use js_sys;
56

67
#[wasm_bindgen]
78
extern {
@@ -13,49 +14,8 @@ extern {
1314
/// Returns whether it's likely we're executing in a browser environment, as
1415
/// opposed to node.js.
1516
pub fn is_browser() -> bool {
16-
// This is a bit tricky to define. The basic crux of this is that we want to
17-
// test if the `self` identifier is defined. That is defined in browsers
18-
// (and web workers!) but not in Node. To that end you might expect:
19-
//
20-
// #[wasm_bindgen]
21-
// extern {
22-
// #[wasm_bindgen(js_name = self)]
23-
// static SELF: JsValue;
24-
// }
25-
//
26-
// *SELF != JsValue::undefined()
27-
//
28-
// this currently, however, throws a "not defined" error in JS because the
29-
// generated function looks like `function() { return self; }` which throws
30-
// an error in Node because `self` isn't defined.
31-
//
32-
// To work around this limitation we instead lookup the value of `self`
33-
// through the `this` object, basically generating `this.self`.
34-
//
35-
// Unfortunately that's also hard to do! In ESM modes the top-level `this`
36-
// object is undefined, meaning that we can't just generate a function that
37-
// returns `this.self` as it'll throw "can't access field `self` of
38-
// `undefined`" whenever ESMs are being used.
39-
//
40-
// So finally we reach the current implementation. According to
41-
// StackOverflow you can access the global object via:
42-
//
43-
// const global = Function('return this')();
44-
//
45-
// I think that's because the manufactured function isn't in "strict" mode.
46-
// It also turns out that non-strict functions will ignore `undefined`
47-
// values for `this` when using the `apply` function. Add it all up, and you
48-
// get the below code:
49-
//
50-
// * Manufacture a function
51-
// * Call `apply` where we specify `this` but the function ignores it
52-
// * Once we have `this`, use a structural getter to get the value of `self`
53-
// * Last but not least, test whether `self` is defined or not.
54-
//
55-
// Whew!
56-
let this = Function::new_no_args("return this")
57-
.call0(&JsValue::undefined())
58-
.unwrap();
59-
assert!(this != JsValue::undefined());
60-
This::from(this).self_() != JsValue::undefined()
17+
// Test whether we're in a browser by seeing if the `self` property is
18+
// defined on the global object, which should in turn only be true in
19+
// browsers.
20+
js_sys::global().unchecked_into::<This>().self_() != JsValue::undefined()
6121
}

crates/web-sys/src/lib.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,14 @@
1515

1616
extern crate wasm_bindgen;
1717
extern crate js_sys;
18+
1819
use js_sys::Object;
1920

21+
#[cfg(feature = "Window")]
22+
pub fn window() -> Option<Window> {
23+
use wasm_bindgen::JsCast;
24+
25+
js_sys::global().dyn_into::<Window>().ok()
26+
}
27+
2028
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
}

crates/webidl-tests/global.js

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
global.global_no_args = () => 3;
2-
global.global_with_args = (a, b) => a + b;
3-
global.global_attribute = 'x';
1+
const map = {
2+
global_no_args: () => 3,
3+
global_with_args: (a, b) => a + b,
4+
global_attribute: 'x',
5+
};
6+
7+
global.get_global = () => map;
48

crates/webidl-tests/global.rs

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
use js_sys::Object;
2+
use wasm_bindgen::prelude::*;
23
use wasm_bindgen_test::*;
34

45
include!(concat!(env!("OUT_DIR"), "/global.rs"));
56

7+
#[wasm_bindgen]
8+
extern {
9+
fn get_global() -> Global;
10+
}
11+
612
#[wasm_bindgen_test]
713
fn works() {
8-
assert_eq!(Global::global_no_args(), 3);
9-
assert_eq!(Global::global_with_args("a", "b"), "ab");
10-
assert_eq!(Global::global_attribute(), "x");
11-
Global::set_global_attribute("y");
12-
assert_eq!(Global::global_attribute(), "y");
14+
let x = get_global();
15+
assert_eq!(x.global_no_args(), 3);
16+
assert_eq!(x.global_with_args("a", "b"), "ab");
17+
assert_eq!(x.global_attribute(), "x");
18+
x.set_global_attribute("y");
19+
assert_eq!(x.global_attribute(), "y");
1320
}

crates/webidl-tests/simple.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,11 @@ global.Unforgeable = class Unforgeable {
8787
}
8888
};
8989

90-
global.m = () => 123;
90+
global.GlobalMethod = class {
91+
m() { return 123; }
92+
};
93+
94+
global.get_global_method = () => new GlobalMethod();
9195

9296
global.Indexing = function () {
9397
return new Proxy({}, {

crates/webidl-tests/simple.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,16 @@ fn nullable_method() {
7272
assert!(f.opt(None) == None);
7373
}
7474

75+
#[wasm_bindgen]
76+
extern {
77+
fn get_global_method() -> GlobalMethod;
78+
}
79+
80+
7581
#[wasm_bindgen_test]
7682
fn global_method() {
77-
assert_eq!(GlobalMethod::m(), 123);
83+
let x = get_global_method();
84+
assert_eq!(x.m(), 123);
7885
}
7986

8087
#[wasm_bindgen_test]

crates/webidl/src/first_pass.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ pub(crate) struct FirstPassRecord<'src> {
4444
pub(crate) struct InterfaceData<'src> {
4545
/// Whether only partial interfaces were encountered
4646
pub(crate) partial: bool,
47-
pub(crate) global: bool,
4847
pub(crate) attributes: Vec<&'src AttributeInterfaceMember<'src>>,
4948
pub(crate) consts: Vec<&'src ConstMember<'src>>,
5049
pub(crate) operations: BTreeMap<OperationId<'src>, OperationData<'src>>,
@@ -373,12 +372,6 @@ fn process_interface_attribute<'src>(
373372
false,
374373
);
375374
}
376-
ExtendedAttribute::Ident(id) if id.lhs_identifier.0 == "Global" => {
377-
record.interfaces.get_mut(self_name).unwrap().global = true;
378-
}
379-
ExtendedAttribute::IdentList(id) if id.identifier.0 == "Global" => {
380-
record.interfaces.get_mut(self_name).unwrap().global = true;
381-
}
382375
_ => {}
383376
}
384377
}

0 commit comments

Comments
 (0)