Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iterating over js values #887

Merged
merged 7 commits into from Sep 25, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/backend/src/codegen.rs
Expand Up @@ -1210,11 +1210,13 @@ impl ToTokens for ast::DictionaryField {
(quote! {
pub fn #name(&mut self, val: #ty) -> &mut Self {
use wasm_bindgen::JsValue;
::js_sys::Reflect::set(
let r = ::js_sys::Reflect::set(
self.obj.as_ref(),
&JsValue::from(stringify!(#name)),
&JsValue::from(val),
);
debug_assert!(r.is_ok(), "setting properties should never fail on our dictionary objects");
let _ = r;
self
}
}).to_tokens(tokens);
Expand Down
230 changes: 166 additions & 64 deletions crates/js-sys/src/lib.rs

Large diffs are not rendered by default.

19 changes: 19 additions & 0 deletions crates/js-sys/tests/wasm/Iterator.js
@@ -0,0 +1,19 @@
exports.get_iterable = () => ["one", "two", "three"];

exports.get_not_iterable = () => new Object;

exports.get_symbol_iterator_throws = () => ({
[Symbol.iterator]: () => { throw new Error("nope"); },
});

exports.get_symbol_iterator_not_function = () => ({
[Symbol.iterator]: 5,
});

exports.get_symbol_iterator_returns_not_object = () => ({
[Symbol.iterator]: () => 5,
});

exports.get_symbol_iterator_returns_object_without_next = () => ({
[Symbol.iterator]: () => new Object,
});
36 changes: 36 additions & 0 deletions crates/js-sys/tests/wasm/Iterator.rs
@@ -0,0 +1,36 @@
use js_sys::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;

#[wasm_bindgen(module = "tests/wasm/Iterator.js")]
extern "C" {
fn get_iterable() -> JsValue;

fn get_not_iterable() -> JsValue;

fn get_symbol_iterator_throws() -> JsValue;

fn get_symbol_iterator_not_function() -> JsValue;

fn get_symbol_iterator_returns_not_object() -> JsValue;

fn get_symbol_iterator_returns_object_without_next() -> JsValue;
}

#[wasm_bindgen_test]
fn try_iter_handles_iteration_protocol() {
assert_eq!(
try_iter(&get_iterable())
.unwrap()
.unwrap()
.map(|x| x.unwrap().as_string().unwrap())
.collect::<Vec<_>>(),
vec!["one", "two", "three"]
);

assert!(try_iter(&get_not_iterable()).unwrap().is_none());
assert!(try_iter(&get_symbol_iterator_throws()).is_err());
assert!(try_iter(&get_symbol_iterator_not_function()).unwrap().is_none());
assert!(try_iter(&get_symbol_iterator_returns_not_object()).unwrap().is_none());
assert!(try_iter(&get_symbol_iterator_returns_object_without_next()).unwrap().is_none());
}
2 changes: 1 addition & 1 deletion crates/js-sys/tests/wasm/JSON.rs
Expand Up @@ -72,7 +72,7 @@ fn stringify() {
fn stringify_error() {
let func = Function::new_no_args("throw new Error(\"rust really rocks\")");
let obj = Object::new();
Reflect::set(obj.as_ref(), &JsValue::from("toJSON"), func.as_ref());
Reflect::set(obj.as_ref(), &JsValue::from("toJSON"), func.as_ref()).unwrap();

let result = JSON::stringify(&JsValue::from(obj));
assert!(result.is_err());
Expand Down
20 changes: 10 additions & 10 deletions crates/js-sys/tests/wasm/JsString.rs
Expand Up @@ -168,7 +168,7 @@ fn locale_compare() {
assert!(js_b.locale_compare(a, &locales, &options) < 0);

locales.push(&"en".into());
Reflect::set(options.as_ref(), &"sensitivity".into(), &"base".into());
Reflect::set(options.as_ref(), &"sensitivity".into(), &"base".into()).unwrap();

assert_eq!(js_a.locale_compare(a, &locales, &options), 0);
assert_eq!(js_a.locale_compare(b, &locales, &options), 0);
Expand Down Expand Up @@ -211,7 +211,7 @@ fn locale_compare() {
assert!(js_ten.locale_compare(two, &locales, &options) > 0);

let locales = Array::new();
Reflect::set(options.as_ref(), &"numeric".into(), &JsValue::TRUE);
Reflect::set(options.as_ref(), &"numeric".into(), &JsValue::TRUE).unwrap();

assert!(js_two.locale_compare(ten, &locales, &options) < 0);
assert!(js_ten.locale_compare(two, &locales, &options) > 0);
Expand All @@ -224,8 +224,8 @@ fn match_() {
let result = JsString::from(s).match_(&re);
let obj = result.unwrap();

assert_eq!(Reflect::get(obj.as_ref(), &"0".into()), "T");
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()), "I");
assert_eq!(Reflect::get(obj.as_ref(), &"0".into()).unwrap(), "T");
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()).unwrap(), "I");

let result = JsString::from("foo").match_(&re);
assert!(result.is_none());
Expand All @@ -235,11 +235,11 @@ fn match_() {
let result = JsString::from(s).match_(&re);
let obj = result.unwrap();

assert_eq!(Reflect::get(obj.as_ref(), &"0".into()), "see Chapter 3.4.5.1");
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()), "Chapter 3.4.5.1");
assert_eq!(Reflect::get(obj.as_ref(), &"2".into()), ".1");
assert_eq!(Reflect::get(obj.as_ref(), &"index".into()), 22);
assert_eq!(Reflect::get(obj.as_ref(), &"input".into()), s);
assert_eq!(Reflect::get(obj.as_ref(), &"0".into()).unwrap(), "see Chapter 3.4.5.1");
assert_eq!(Reflect::get(obj.as_ref(), &"1".into()).unwrap(), "Chapter 3.4.5.1");
assert_eq!(Reflect::get(obj.as_ref(), &"2".into()).unwrap(), ".1");
assert_eq!(Reflect::get(obj.as_ref(), &"index".into()).unwrap(), 22);
assert_eq!(Reflect::get(obj.as_ref(), &"input".into()).unwrap(), s);
}

#[wasm_bindgen_test]
Expand Down Expand Up @@ -494,7 +494,7 @@ fn value_of() {
fn raw() {
let call_site = Object::new();
let raw = Array::of3(&"foo".into(), &"bar".into(), &"123".into());
Reflect::set(&call_site.as_ref(), &"raw".into(), &raw.into());
Reflect::set(&call_site.as_ref(), &"raw".into(), &raw.into()).unwrap();
assert_eq!(JsString::raw_2(&call_site, "5", "JavaScript").unwrap(), "foo5barJavaScript123");
let substitutions = Array::of2(&"5".into(), &"JavaScript".into());
assert_eq!(JsString::raw(&call_site, &substitutions).unwrap(), "foo5barJavaScript123");
Expand Down
4 changes: 2 additions & 2 deletions crates/js-sys/tests/wasm/MapIterator.rs
Expand Up @@ -11,8 +11,8 @@ fn entries() {
let next = entries.next().unwrap();
assert_eq!(next.done(), false);
assert!(next.value().is_object());
assert_eq!(Reflect::get(&next.value(), &0.into()), "uno");
assert_eq!(Reflect::get(&next.value(), &1.into()), 1);
assert_eq!(Reflect::get(&next.value(), &0.into()).unwrap(), "uno");
assert_eq!(Reflect::get(&next.value(), &1.into()).unwrap(), 1);

let next = entries.next().unwrap();
assert!(next.done());
Expand Down
20 changes: 10 additions & 10 deletions crates/js-sys/tests/wasm/Object.rs
Expand Up @@ -57,23 +57,23 @@ fn assign() {
let c = JsValue::from("c");

let target = Object::new();
Reflect::set(target.as_ref(), a.as_ref(), a.as_ref());
Reflect::set(target.as_ref(), a.as_ref(), a.as_ref()).unwrap();

let src1 = Object::new();
Reflect::set(src1.as_ref(), &a, &c);
Reflect::set(src1.as_ref(), &a, &c).unwrap();

let src2 = Object::new();
Reflect::set(src2.as_ref(), &b, &b);
Reflect::set(src2.as_ref(), &b, &b).unwrap();

let src3 = Object::new();
Reflect::set(src3.as_ref(), &c, &c);
Reflect::set(src3.as_ref(), &c, &c).unwrap();

let res = Object::assign3(&target, &src1, &src2, &src3);

assert!(Object::is(target.as_ref(), res.as_ref()));
assert_eq!(Reflect::get(target.as_ref(), &a), c);
assert_eq!(Reflect::get(target.as_ref(), &b), b);
assert_eq!(Reflect::get(target.as_ref(), &c), c);
assert_eq!(Reflect::get(target.as_ref(), &a).unwrap(), c);
assert_eq!(Reflect::get(target.as_ref(), &b).unwrap(), b);
assert_eq!(Reflect::get(target.as_ref(), &c).unwrap(), c);
}

#[wasm_bindgen_test]
Expand Down Expand Up @@ -102,8 +102,8 @@ fn define_properties() {
let descriptor = DefinePropertyAttrs::from(JsValue::from(Object::new()));
descriptor.set_value(&42.into());
let descriptor = JsValue::from(descriptor);
Reflect::set(props.as_ref(), &JsValue::from("bar"), &descriptor);
Reflect::set(props.as_ref(), &JsValue::from("car"), &descriptor);
Reflect::set(props.as_ref(), &JsValue::from("bar"), &descriptor).unwrap();
Reflect::set(props.as_ref(), &JsValue::from("car"), &descriptor).unwrap();
let foo = foo_42();
let foo = Object::define_properties(&foo, &props);
assert!(foo.has_own_property(&"bar".into()));
Expand Down Expand Up @@ -136,7 +136,7 @@ fn get_own_property_descriptor() {
fn get_own_property_descriptors() {
let foo = foo_42();
let descriptors = Object::get_own_property_descriptors(&foo);
let foo_desc = Reflect::get(&descriptors, &"foo".into());
let foo_desc = Reflect::get(&descriptors, &"foo".into()).unwrap();
assert_eq!(PropertyDescriptor::from(foo_desc).value(), 42);
}

Expand Down
16 changes: 16 additions & 0 deletions crates/js-sys/tests/wasm/Reflect.js
Expand Up @@ -23,3 +23,19 @@ exports.Rectangle2 = class {
return x === y;
}
};

exports.throw_all_the_time = () => new Proxy({}, {
getPrototypeOf() { throw new Error("nope"); },
setPrototypeOf() { throw new Error("nope"); },
isExtensible() { throw new Error("nope"); },
preventExtensions() { throw new Error("nope"); },
getOwnPropertyDescriptor() { throw new Error("nope"); },
defineProperty() { throw new Error("nope"); },
has() { throw new Error("nope"); },
get() { throw new Error("nope"); },
set() { throw new Error("nope"); },
deleteProperty() { throw new Error("nope"); },
ownKeys() { throw new Error("nope"); },
apply() { throw new Error("nope"); },
construct() { throw new Error("nope"); },
});