Implement the Iterator trait for JS iterators

This commit implements the standard library's `Iterator` trait for the
`js_sys::Iterator` type, using the iterator protocol described on [MDN]

Closes #777

[MDN]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols
This commit is contained in:
Alex Crichton 2018-09-06 21:18:42 -07:00
parent f18b10ca52
commit f2608d3155
2 changed files with 101 additions and 0 deletions

View File

@ -1174,6 +1174,79 @@ extern {
pub fn next(this: &Iterator) -> Result<IteratorNext, JsValue>;
}
pub struct Iter<'a> {
js: &'a Iterator,
state: IterState,
}
pub struct IntoIter {
js: Iterator,
state: IterState,
}
struct IterState {
done: bool,
}
impl<'a> IntoIterator for &'a Iterator {
type Item = Result<JsValue, JsValue>;
type IntoIter = Iter<'a>;
fn into_iter(self) -> Iter<'a> {
Iter { js: self, state: IterState::new() }
}
}
impl<'a> std::iter::Iterator for Iter<'a> {
type Item = Result<JsValue, JsValue>;
fn next(&mut self) -> Option<Self::Item> {
self.state.next(self.js)
}
}
impl IntoIterator for Iterator {
type Item = Result<JsValue, JsValue>;
type IntoIter = IntoIter;
fn into_iter(self) -> IntoIter {
IntoIter { js: self, state: IterState::new() }
}
}
impl std::iter::Iterator for IntoIter {
type Item = Result<JsValue, JsValue>;
fn next(&mut self) -> Option<Self::Item> {
self.state.next(&self.js)
}
}
impl IterState {
fn new() -> IterState {
IterState { done: false }
}
fn next(&mut self, js: &Iterator) -> Option<Result<JsValue, JsValue>> {
if self.done {
return None
}
let next = match js.next() {
Ok(val) => val,
Err(e) => {
self.done = true;
return Some(Err(e))
}
};
if next.done() {
self.done = true;
None
} else {
Some(Ok(next.value()))
}
}
}
// IteratorNext
#[wasm_bindgen]
extern {

View File

@ -89,3 +89,31 @@ fn set_inheritance() {
assert!(set.is_instance_of::<Object>());
let _: &Object = set.as_ref();
}
#[wasm_bindgen_test]
fn keys() {
let set = Set::new(&JsValue::undefined());
set.add(&1.into());
set.add(&2.into());
set.add(&3.into());
let list = set.keys().into_iter().map(|e| e.unwrap()).collect::<Vec<_>>();
assert_eq!(list.len(), 3);
assert!(list.iter().any(|l| *l == 1));
assert!(list.iter().any(|l| *l == 2));
assert!(list.iter().any(|l| *l == 3));
}
#[wasm_bindgen_test]
fn values() {
let set = Set::new(&JsValue::undefined());
set.add(&1.into());
set.add(&2.into());
set.add(&3.into());
let list = set.values().into_iter().map(|e| e.unwrap()).collect::<Vec<_>>();
assert_eq!(list.len(), 3);
assert!(list.iter().any(|l| *l == 1));
assert!(list.iter().any(|l| *l == 2));
assert!(list.iter().any(|l| *l == 3));
}