Skip to content

Commit a1d9039

Browse files
Pauanalexcrichton
authored andcommitted
Adding in support for async iterators (#1895)
* Adding in support for async iterators * Adding in some unit tests for asyncIterator * Fixing unit tests * Fixing UI tests
1 parent 203d86f commit a1d9039

File tree

4 files changed

+71
-1
lines changed

4 files changed

+71
-1
lines changed

crates/js-sys/src/lib.rs

+26
Original file line numberDiff line numberDiff line change
@@ -1349,6 +1349,25 @@ impl Iterator {
13491349
}
13501350
}
13511351

1352+
// Async Iterator
1353+
#[wasm_bindgen]
1354+
extern "C" {
1355+
/// Any object that conforms to the JS async iterator protocol. For example,
1356+
/// something returned by `myObject[Symbol.asyncIterator]()`.
1357+
///
1358+
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of)
1359+
#[derive(Clone, Debug)]
1360+
#[wasm_bindgen(is_type_of = Iterator::looks_like_iterator)]
1361+
pub type AsyncIterator;
1362+
1363+
/// The next method always has to return a Promise which resolves to an object
1364+
/// with appropriate properties including done and value. If a non-object value
1365+
/// gets returned (such as false or undefined), a TypeError ("iterator.next()
1366+
/// returned a non-object value") will be thrown.
1367+
#[wasm_bindgen(catch, method, structural)]
1368+
pub fn next(this: &AsyncIterator) -> Result<Promise, JsValue>;
1369+
}
1370+
13521371
/// An iterator over the JS `Symbol.iterator` iteration protocol.
13531372
///
13541373
/// Use the `IntoIterator for &js_sys::Iterator` implementation to create this.
@@ -4165,6 +4184,13 @@ extern "C" {
41654184
#[wasm_bindgen(static_method_of = Symbol, getter, structural, js_name = isConcatSpreadable)]
41664185
pub fn is_concat_spreadable() -> Symbol;
41674186

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

crates/js-sys/tests/wasm/Symbol.js

+35
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,41 @@ exports.test_iterator = function(sym) {
3636
assert.deepEqual([...iterable1], [1, 2, 3]);
3737
};
3838

39+
exports.test_async_iterator = async function(sym) {
40+
const iterable1 = new Object();
41+
42+
iterable1[sym] = function () {
43+
let done = false;
44+
45+
return {
46+
next() {
47+
if (done) {
48+
return Promise.resolve({
49+
done: true,
50+
value: 1
51+
});
52+
53+
} else {
54+
done = true;
55+
56+
return Promise.resolve({
57+
done: false,
58+
value: 0
59+
});
60+
}
61+
}
62+
};
63+
};
64+
65+
const values = [];
66+
67+
for await (let value of iterable1) {
68+
values.push(value);
69+
}
70+
71+
assert.deepEqual(values, [0]);
72+
};
73+
3974
exports.test_match = function(sym) {
4075
const regexp1 = /foo/;
4176
assert.throws(() => '/foo/'.startsWith(regexp1));

crates/js-sys/tests/wasm/Symbol.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
use js_sys::*;
22
use wasm_bindgen::prelude::*;
33
use wasm_bindgen_test::*;
4+
use wasm_bindgen_futures::JsFuture;
45

56
#[wasm_bindgen(module = "tests/wasm/Symbol.js")]
67
extern "C" {
78
fn test_has_instance(sym: &Symbol);
89
fn test_is_concat_spreadable(sym: &Symbol);
910
fn test_iterator(sym: &Symbol);
11+
fn test_async_iterator(sym: &Symbol) -> Promise;
1012
fn test_match(sym: &Symbol);
1113
fn test_replace(sym: &Symbol);
1214
fn test_search(sym: &Symbol);
@@ -37,6 +39,11 @@ fn iterator() {
3739
test_iterator(&Symbol::iterator());
3840
}
3941

42+
#[wasm_bindgen_test]
43+
async fn async_iterator() {
44+
JsFuture::from(test_async_iterator(&Symbol::async_iterator())).await.unwrap_throw();
45+
}
46+
4047
#[wasm_bindgen_test]
4148
fn match_() {
4249
test_match(&Symbol::match_());
@@ -89,12 +96,14 @@ fn key_for() {
8996
let sym = Symbol::for_("foo");
9097
assert_eq!(Symbol::key_for(&sym), "foo");
9198
assert!(Symbol::key_for(&Symbol::iterator()).is_undefined());
99+
assert!(Symbol::key_for(&Symbol::async_iterator()).is_undefined());
92100
assert!(Symbol::key_for(&gensym(JsValue::undefined())).is_undefined());
93101
}
94102

95103
#[wasm_bindgen_test]
96104
fn to_string() {
97105
assert_eq!(Symbol::iterator().to_string(), "Symbol(Symbol.iterator)");
106+
assert_eq!(Symbol::async_iterator().to_string(), "Symbol(Symbol.asyncIterator)");
98107
assert_eq!(Symbol::for_("foo").to_string(), "Symbol(foo)");
99108
assert_eq!(gensym("desc".into()).to_string(), "Symbol(desc)");
100109
}

crates/macro/ui-tests/async-errors.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ error[E0277]: the trait bound `wasm_bindgen::JsValue: std::convert::From<BadType
3131
<wasm_bindgen::JsValue as std::convert::From<&'a std::string::String>>
3232
<wasm_bindgen::JsValue as std::convert::From<&'a str>>
3333
<wasm_bindgen::JsValue as std::convert::From<MyType>>
34-
and 61 others
34+
and 62 others
3535
= note: required because of the requirements on the impl of `std::convert::Into<wasm_bindgen::JsValue>` for `BadType`
3636
= note: required because of the requirements on the impl of `wasm_bindgen::__rt::IntoJsResult` for `BadType`
3737
= note: required by `wasm_bindgen::__rt::IntoJsResult::into_js_result`

0 commit comments

Comments
 (0)