Skip to content

Commit

Permalink
Adding in support for async iterators (#1895)
Browse files Browse the repository at this point in the history
* Adding in support for async iterators

* Adding in some unit tests for asyncIterator

* Fixing unit tests

* Fixing UI tests
  • Loading branch information
Pauan authored and alexcrichton committed Dec 4, 2019
1 parent 203d86f commit a1d9039
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 1 deletion.
26 changes: 26 additions & 0 deletions crates/js-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,25 @@ impl Iterator {
}
}

// Async Iterator
#[wasm_bindgen]
extern "C" {
/// Any object that conforms to the JS async iterator protocol. For example,
/// something returned by `myObject[Symbol.asyncIterator]()`.
///
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of)
#[derive(Clone, Debug)]
#[wasm_bindgen(is_type_of = Iterator::looks_like_iterator)]
pub type AsyncIterator;

/// The next method always has to return a Promise which resolves to an object
/// with appropriate properties including done and value. If a non-object value
/// gets returned (such as false or undefined), a TypeError ("iterator.next()
/// returned a non-object value") will be thrown.
#[wasm_bindgen(catch, method, structural)]
pub fn next(this: &AsyncIterator) -> Result<Promise, JsValue>;
}

/// An iterator over the JS `Symbol.iterator` iteration protocol.
///
/// Use the `IntoIterator for &js_sys::Iterator` implementation to create this.
Expand Down Expand Up @@ -4165,6 +4184,13 @@ extern "C" {
#[wasm_bindgen(static_method_of = Symbol, getter, structural, js_name = isConcatSpreadable)]
pub fn is_concat_spreadable() -> Symbol;

/// The `Symbol.asyncIterator` well-known symbol specifies the default AsyncIterator for an object.
/// If this property is set on an object, it is an async iterable and can be used in a `for await...of` loop.
///
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/asyncIterator)
#[wasm_bindgen(static_method_of = Symbol, getter, structural, js_name = asyncIterator)]
pub fn async_iterator() -> Symbol;

/// The `Symbol.iterator` well-known symbol specifies the default iterator
/// for an object. Used by `for...of`.
///
Expand Down
35 changes: 35 additions & 0 deletions crates/js-sys/tests/wasm/Symbol.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,41 @@ exports.test_iterator = function(sym) {
assert.deepEqual([...iterable1], [1, 2, 3]);
};

exports.test_async_iterator = async function(sym) {
const iterable1 = new Object();

iterable1[sym] = function () {
let done = false;

return {
next() {
if (done) {
return Promise.resolve({
done: true,
value: 1
});

} else {
done = true;

return Promise.resolve({
done: false,
value: 0
});
}
}
};
};

const values = [];

for await (let value of iterable1) {
values.push(value);
}

assert.deepEqual(values, [0]);
};

exports.test_match = function(sym) {
const regexp1 = /foo/;
assert.throws(() => '/foo/'.startsWith(regexp1));
Expand Down
9 changes: 9 additions & 0 deletions crates/js-sys/tests/wasm/Symbol.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
use js_sys::*;
use wasm_bindgen::prelude::*;
use wasm_bindgen_test::*;
use wasm_bindgen_futures::JsFuture;

#[wasm_bindgen(module = "tests/wasm/Symbol.js")]
extern "C" {
fn test_has_instance(sym: &Symbol);
fn test_is_concat_spreadable(sym: &Symbol);
fn test_iterator(sym: &Symbol);
fn test_async_iterator(sym: &Symbol) -> Promise;
fn test_match(sym: &Symbol);
fn test_replace(sym: &Symbol);
fn test_search(sym: &Symbol);
Expand Down Expand Up @@ -37,6 +39,11 @@ fn iterator() {
test_iterator(&Symbol::iterator());
}

#[wasm_bindgen_test]
async fn async_iterator() {
JsFuture::from(test_async_iterator(&Symbol::async_iterator())).await.unwrap_throw();
}

#[wasm_bindgen_test]
fn match_() {
test_match(&Symbol::match_());
Expand Down Expand Up @@ -89,12 +96,14 @@ fn key_for() {
let sym = Symbol::for_("foo");
assert_eq!(Symbol::key_for(&sym), "foo");
assert!(Symbol::key_for(&Symbol::iterator()).is_undefined());
assert!(Symbol::key_for(&Symbol::async_iterator()).is_undefined());
assert!(Symbol::key_for(&gensym(JsValue::undefined())).is_undefined());
}

#[wasm_bindgen_test]
fn to_string() {
assert_eq!(Symbol::iterator().to_string(), "Symbol(Symbol.iterator)");
assert_eq!(Symbol::async_iterator().to_string(), "Symbol(Symbol.asyncIterator)");
assert_eq!(Symbol::for_("foo").to_string(), "Symbol(foo)");
assert_eq!(gensym("desc".into()).to_string(), "Symbol(desc)");
}
Expand Down
2 changes: 1 addition & 1 deletion crates/macro/ui-tests/async-errors.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: std::convert::From<BadType
<wasm_bindgen::JsValue as std::convert::From<&'a std::string::String>>
<wasm_bindgen::JsValue as std::convert::From<&'a str>>
<wasm_bindgen::JsValue as std::convert::From<MyType>>
and 61 others
and 62 others
= note: required because of the requirements on the impl of `std::convert::Into<wasm_bindgen::JsValue>` for `BadType`
= note: required because of the requirements on the impl of `wasm_bindgen::__rt::IntoJsResult` for `BadType`
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`
Expand Down

0 comments on commit a1d9039

Please sign in to comment.