broccoli_rob
broccoli_rob

Reputation: 550

Can't convert Iterators into js_sys::Array

I'm trying to implement a method to send an array of u32 (eventually an array of arrays of usize, if possible), since you can't just declare a public array field on a wasm_bindgen type. However, using the example outlined in the wasm_bindgen PR 1749, I can't seem to convert arrays or slices to a js_sys::Array; it only works for Vecs. My question is, why? See below

pub fn test() -> js_sys::Array {
    let arr: [u32; 5] = [0,1,2,3,4];
    let slice = &arr[0..2];
    let vec: Vec<u32> = vec![0,1,2];
    arr.into_iter().map(JsValue::from).collect() // This doesn't work
    slice.into_iter().map(JsValue::from).collect() // Also doesn't work
    vec.into_iter().map(JsValue::from).collect() // Works as expected!     
}

The specific error is: the trait 'wasm_bindgen::cast::JsCast' is not implemented for 'u32'

The array and slice examples don't seem to work for any number type, ints or floats. My only thought is because the implementation in PR 1749 seems to expect a ref, and arrays are allocated on the stack that the FromIterator is not valid for items in an array?

Is there some other way to achieve what I'm trying to do with the array (passing across the boundary to JS through wasm_bindgen), or if not, why? I'd be very interested to know.

Upvotes: 2

Views: 1015

Answers (1)

pretzelhammer
pretzelhammer

Reputation: 15105

Although Rust arrays and slices have an into_iter method it returns the same Iterator as the iter method does which iterates over references to values instead of the values themselves. Yes, this is confusing. Since JsValue::from is implemented for u32 but not for &u32 you can take your Iterator<Item = &u32> and convert it to a Iterator<Item = u32> using the copied method. Fixed working examples:

use wasm_bindgen::JsValue;
use js_sys::Array;

fn array_to_js_array(array: [u32; 5]) -> Array {
    array.iter().copied().map(JsValue::from).collect()     
}

fn slice_to_js_array(slice: &[u32]) -> Array {
    slice.iter().copied().map(JsValue::from).collect()    
}

fn vec_to_js_array(vec: Vec<u32>) -> Array {
    vec.into_iter().map(JsValue::from).collect()    
}

Upvotes: 2

Related Questions