diff --git a/crates/js-sys/src/lib.rs b/crates/js-sys/src/lib.rs index 6dfa1bffed4..8fecd9e6582 100644 --- a/crates/js-sys/src/lib.rs +++ b/crates/js-sys/src/lib.rs @@ -425,6 +425,61 @@ extern "C" { pub fn unshift(this: &Array, value: &JsValue) -> u32; } +/// Iterator returned by `Array::iter` +#[derive(Debug, Clone)] +pub struct ArrayIter<'a> { + range: std::ops::Range, + array: &'a Array, +} + +impl<'a> std::iter::Iterator for ArrayIter<'a> { + type Item = JsValue; + + fn next(&mut self) -> Option { + let index = self.range.next()?; + Some(self.array.get(index)) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.range.size_hint() + } +} + +impl<'a> std::iter::DoubleEndedIterator for ArrayIter<'a> { + fn next_back(&mut self) -> Option { + let index = self.range.next_back()?; + Some(self.array.get(index)) + } +} + +impl<'a> std::iter::FusedIterator for ArrayIter<'a> {} + +impl<'a> std::iter::ExactSizeIterator for ArrayIter<'a> {} + +impl Array { + /// Returns an iterator over the values of the JS array. + pub fn iter(&self) -> ArrayIter<'_> { + ArrayIter { + range: 0..self.length(), + array: self, + } + } + + /// Converts the JS array into a new Vec. + pub fn to_vec(&self) -> Vec { + let len = self.length(); + + let mut output = Vec::with_capacity(len as usize); + + for i in 0..len { + output.push(self.get(i)); + } + + output + } +} + // TODO pre-initialize the Array with the correct length using TrustedLen impl std::iter::FromIterator for Array where diff --git a/crates/js-sys/tests/wasm/Array.rs b/crates/js-sys/tests/wasm/Array.rs index 44050325d86..78e5f0a2c23 100644 --- a/crates/js-sys/tests/wasm/Array.rs +++ b/crates/js-sys/tests/wasm/Array.rs @@ -81,6 +81,69 @@ fn from_iter() { ); } +#[wasm_bindgen_test] +fn to_vec() { + let array = vec![JsValue::from("a"), JsValue::from("b"), JsValue::from("c")] + .into_iter() + .collect::(); + + assert_eq!(array.to_vec(), vec![JsValue::from("a"), JsValue::from("b"), JsValue::from("c")]); +} + +#[wasm_bindgen_test] +fn iter() { + let array = vec![JsValue::from("a"), JsValue::from("b"), JsValue::from("c")] + .into_iter() + .collect::(); + + assert_eq!(array.iter().collect::>(), vec![JsValue::from("a"), JsValue::from("b"), JsValue::from("c")]); + + let mut iter = array.iter(); + + assert_eq!(iter.size_hint(), (3, Some(3))); + assert_eq!(iter.next(), Some(JsValue::from("a"))); + + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next_back(), Some(JsValue::from("c"))); + + assert_eq!(iter.size_hint(), (1, Some(1))); + assert_eq!(iter.next_back(), Some(JsValue::from("b"))); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next_back(), None); + + let mut iter = array.iter(); + + assert_eq!(iter.size_hint(), (3, Some(3))); + assert_eq!(iter.next(), Some(JsValue::from("a"))); + + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next(), Some(JsValue::from("b"))); + + assert_eq!(iter.size_hint(), (1, Some(1))); + assert_eq!(iter.next(), Some(JsValue::from("c"))); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next(), None); + + let mut iter = array.iter(); + + assert_eq!(iter.size_hint(), (3, Some(3))); + assert_eq!(iter.next_back(), Some(JsValue::from("c"))); + + assert_eq!(iter.size_hint(), (2, Some(2))); + assert_eq!(iter.next_back(), Some(JsValue::from("b"))); + + assert_eq!(iter.size_hint(), (1, Some(1))); + assert_eq!(iter.next_back(), Some(JsValue::from("a"))); + + assert_eq!(iter.size_hint(), (0, Some(0))); + assert_eq!(iter.next_back(), None); +} + #[wasm_bindgen_test] fn new_with_length() { let array = Array::new_with_length(5);