Skip to content

Commit 2f524ee

Browse files
committed
Leverage new is_type_of for iterator protocol
Treats any object of shape `{ next: function }` as an iterator via new `is_type_of` method. This is consistent with JavaScript iteration protocol which we already respect. Also fixes a minor issue that `is_function` was unnecessarily called twice (once explicitly and once as part of `dyn_into` which now does the same check).
1 parent c4776be commit 2f524ee

File tree

1 file changed

+27
-23
lines changed

1 file changed

+27
-23
lines changed

crates/js-sys/src/lib.rs

Lines changed: 27 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ extern "C" {
10251025
///
10261026
/// [MDN documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols)
10271027
#[derive(Clone, Debug)]
1028+
#[wasm_bindgen(is_type_of = Iterator::looks_like_iterator)]
10281029
pub type Iterator;
10291030

10301031
/// The next method always has to return an object with appropriate
@@ -1035,6 +1036,26 @@ extern "C" {
10351036
pub fn next(this: &Iterator) -> Result<IteratorNext, JsValue>;
10361037
}
10371038

1039+
impl Iterator {
1040+
fn looks_like_iterator(it: &JsValue) -> bool {
1041+
#[wasm_bindgen]
1042+
extern "C" {
1043+
type MaybeIterator;
1044+
1045+
#[wasm_bindgen(method, getter)]
1046+
fn next(this: &MaybeIterator) -> JsValue;
1047+
}
1048+
1049+
if !it.is_object() {
1050+
return false;
1051+
}
1052+
1053+
let it = it.unchecked_ref::<MaybeIterator>();
1054+
1055+
it.next().is_function()
1056+
}
1057+
}
1058+
10381059
/// An iterator over the JS `Symbol.iterator` iteration protocol.
10391060
///
10401061
/// Use the `IntoIterator for &js_sys::Iterator` implementation to create this.
@@ -1123,37 +1144,20 @@ impl IterState {
11231144
/// Create an iterator over `val` using the JS iteration protocol and
11241145
/// `Symbol.iterator`.
11251146
pub fn try_iter(val: &JsValue) -> Result<Option<IntoIter>, JsValue> {
1126-
#[wasm_bindgen]
1127-
extern "C" {
1128-
type MaybeIterator;
1129-
1130-
#[wasm_bindgen(method, getter)]
1131-
fn next(this: &MaybeIterator) -> JsValue;
1132-
}
1133-
11341147
let iter_sym = Symbol::iterator();
11351148
let iter_fn = Reflect::get(val, iter_sym.as_ref())?;
1136-
if !iter_fn.is_function() {
1137-
return Ok(None);
1138-
}
11391149

11401150
let iter_fn: Function = match iter_fn.dyn_into() {
11411151
Ok(iter_fn) => iter_fn,
1142-
Err(_) => return Ok(None)
1152+
Err(_) => return Ok(None),
11431153
};
1144-
let it = iter_fn.call0(val)?;
1145-
if !it.is_object() {
1146-
return Ok(None);
1147-
}
11481154

1149-
let next = it.unchecked_ref::<MaybeIterator>().next();
1155+
let it: Iterator = match iter_fn.call0(val)?.dyn_into() {
1156+
Ok(it) => it,
1157+
Err(_) => return Ok(None),
1158+
};
11501159

1151-
Ok(if next.is_function() {
1152-
let it: Iterator = it.unchecked_into();
1153-
Some(it.into_iter())
1154-
} else {
1155-
None
1156-
})
1160+
Ok(Some(it.into_iter()))
11571161
}
11581162

11591163
// IteratorNext

0 commit comments

Comments
 (0)