wasm_array_cp/
lib.rs

1#![doc = include_str!("../README.md")]
2
3use js_sys::{
4    BigInt64Array, BigUint64Array, Float32Array, Float64Array, Int16Array, Int32Array, Int8Array,
5    Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray, WebAssembly,
6};
7use wasm_bindgen::{prelude::wasm_bindgen, JsCast};
8
9#[wasm_bindgen(module = "/src/copy.js")]
10extern "C" {
11    type JSArrayBufferCopy;
12
13    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI8Slice)]
14    fn to_i8_slice(memory: &WebAssembly::Memory, buffer: &Int8Array, dst: *mut i8, len: usize);
15    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI8Array)]
16    fn to_i8_array(memory: &WebAssembly::Memory, src: *const i8, len: usize, dst: &Int8Array);
17
18    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI16Slice)]
19    fn to_i16_slice(memory: &WebAssembly::Memory, buffer: &Int16Array, dst: *mut i16, len: usize);
20    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI16Array)]
21    fn to_i16_array(memory: &WebAssembly::Memory, src: *const i16, len: usize, dst: &Int16Array);
22
23    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI32Slice)]
24    fn to_i32_slice(memory: &WebAssembly::Memory, buffer: &Int32Array, dst: *mut i32, len: usize);
25    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toI32Array)]
26    fn to_i32_array(memory: &WebAssembly::Memory, src: *const i32, len: usize, dst: &Int32Array);
27
28    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU8Slice)]
29    fn to_u8_slice(memory: &WebAssembly::Memory, buffer: &Uint8Array, dst: *mut u8, len: usize);
30    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU8Array)]
31    fn to_u8_array(memory: &WebAssembly::Memory, src: *const u8, len: usize, dst: &Uint8Array);
32
33    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU8CSlice)]
34    fn to_u8c_slice(
35        memory: &WebAssembly::Memory,
36        buffer: &Uint8ClampedArray,
37        dst: *mut u8,
38        len: usize,
39    );
40    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU8CArray)]
41    fn to_u8c_array(
42        memory: &WebAssembly::Memory,
43        src: *const u8,
44        len: usize,
45        dst: &Uint8ClampedArray,
46    );
47
48    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU16Slice)]
49    fn to_u16_slice(memory: &WebAssembly::Memory, buffer: &Uint16Array, dst: *mut u16, len: usize);
50    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU16Array)]
51    fn to_u16_array(memory: &WebAssembly::Memory, src: *const u16, len: usize, dst: &Uint16Array);
52
53    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU32Slice)]
54    fn to_u32_slice(memory: &WebAssembly::Memory, buffer: &Uint32Array, dst: *mut u32, len: usize);
55    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toU32Array)]
56    fn to_u32_array(memory: &WebAssembly::Memory, src: *const u32, len: usize, dst: &Uint32Array);
57
58    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toF32Slice)]
59    fn to_f32_slice(memory: &WebAssembly::Memory, buffer: &Float32Array, dst: *mut f32, len: usize);
60    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toF32Array)]
61    fn to_f32_array(memory: &WebAssembly::Memory, src: *const f32, len: usize, dst: &Float32Array);
62
63    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toF64Slice)]
64    fn to_f64_slice(memory: &WebAssembly::Memory, buffer: &Float64Array, dst: *mut f64, len: usize);
65    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toF64Array)]
66    fn to_f64_array(memory: &WebAssembly::Memory, src: *const f64, len: usize, dst: &Float64Array);
67
68    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toBigInt64Slice)]
69    fn to_big_i64_slice(
70        memory: &WebAssembly::Memory,
71        buffer: &BigInt64Array,
72        dst: *mut i64,
73        len: usize,
74    );
75    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toBigInt64Array)]
76    fn to_big_i64_array(
77        memory: &WebAssembly::Memory,
78        src: *const i64,
79        len: usize,
80        dst: &BigInt64Array,
81    );
82
83    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toBigUint64Slice)]
84    fn to_big_u64_slice(
85        memory: &WebAssembly::Memory,
86        buffer: &BigUint64Array,
87        dst: *mut u64,
88        len: usize,
89    );
90    #[wasm_bindgen(static_method_of = JSArrayBufferCopy, js_name = toBigUint64Array)]
91    fn to_big_u64_array(
92        memory: &WebAssembly::Memory,
93        src: *const u64,
94        len: usize,
95        dst: &BigUint64Array,
96    );
97}
98
99/// Copy array buffer on the js side.
100pub trait ArrayBufferCopy<T> {
101    /// Copy slice to js array, return js typed array.
102    fn from_slice(src: &[T]) -> Self;
103    /// Copy slice to js array.
104    fn copy_from(&self, src: &[T]);
105    /// Copy js array to slice.
106    fn copy_to(&self, dst: &mut [T]);
107    /// Copy js array to slice, return `Vec<T>`.
108    fn to_vec(&self) -> Vec<T>;
109}
110
111macro_rules! copy_impl {
112    ($(#[doc = $ctor:literal] #[doc = $mdn:literal] ($js:ident: $rust:ident, $to_rust:expr, $to_js:expr),)*) => ($(
113        impl ArrayBufferCopy<$rust> for $js {
114            fn from_slice(src: &[$rust]) -> Self {
115                let dst = $js::new_with_length(src.len() as u32);
116                ArrayBufferCopy::copy_from(&dst, src);
117                dst
118            }
119            fn copy_from(&self, src: &[$rust]) {
120                assert!(
121                    self.length() as usize == src.len(),
122                    "src and dst have different size"
123                );
124                let buf = wasm_bindgen::memory();
125                let mem = buf.unchecked_ref::<WebAssembly::Memory>();
126                $to_js(mem, src.as_ptr(), src.len(), self);
127            }
128            fn copy_to(&self, dst: &mut [$rust]) {
129                assert!(
130                    self.length() as usize == dst.len(),
131                    "src and dst have different size"
132                );
133                let buf = wasm_bindgen::memory();
134                let mem = buf.unchecked_ref::<WebAssembly::Memory>();
135                $to_rust(mem, self, dst.as_mut_ptr(), dst.len());
136            }
137            fn to_vec(&self) -> Vec<$rust> {
138                let mut dst = vec![$rust::default(); self.length() as usize];
139                ArrayBufferCopy::copy_to(self, &mut dst);
140                dst
141            }
142        }
143    )*);
144}
145
146copy_impl! {
147    /// `Int8Array()`
148    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int8Array
149    (Int8Array: i8, JSArrayBufferCopy::to_i8_slice, JSArrayBufferCopy::to_i8_array),
150
151    /// `Int16Array()`
152    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int16Array
153    (Int16Array: i16, JSArrayBufferCopy::to_i16_slice, JSArrayBufferCopy::to_i16_array),
154
155    /// `Int32Array()`
156    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Int32Array
157    (Int32Array: i32, JSArrayBufferCopy::to_i32_slice, JSArrayBufferCopy::to_i32_array),
158
159    /// `Uint8Array()`
160    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
161    (Uint8Array: u8, JSArrayBufferCopy::to_u8_slice, JSArrayBufferCopy::to_u8_array),
162
163    /// `Uint8ClampedArray()`
164    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8ClampedArray
165    (Uint8ClampedArray: u8, JSArrayBufferCopy::to_u8c_slice, JSArrayBufferCopy::to_u8c_array),
166
167    /// `Uint16Array()`
168    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint16Array
169    (Uint16Array: u16, JSArrayBufferCopy::to_u16_slice, JSArrayBufferCopy::to_u16_array),
170
171    /// `Uint32Array()`
172    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint32Array
173    (Uint32Array: u32, JSArrayBufferCopy::to_u32_slice, JSArrayBufferCopy::to_u32_array),
174
175    /// `Float32Array()`
176    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float32Array
177    (Float32Array: f32, JSArrayBufferCopy::to_f32_slice, JSArrayBufferCopy::to_f32_array),
178
179    /// `Float64Array()`
180    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Float64Array
181    (Float64Array: f64, JSArrayBufferCopy::to_f64_slice, JSArrayBufferCopy::to_f64_array),
182
183    /// `BigInt64Array()`
184    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt64Array
185    (BigInt64Array: i64, JSArrayBufferCopy::to_big_i64_slice, JSArrayBufferCopy::to_big_i64_array),
186
187    /// `BigUint64Array()`
188    /// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigUint64Array
189    (BigUint64Array: u64, JSArrayBufferCopy::to_big_u64_slice, JSArrayBufferCopy::to_big_u64_array),
190}
191
192#[cfg(test)]
193mod tests {
194    wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
195
196    use super::ArrayBufferCopy;
197    use js_sys::{
198        BigInt64Array, BigUint64Array, Float32Array, Float64Array, Int16Array, Int32Array,
199        Int8Array, Uint16Array, Uint32Array, Uint8Array, Uint8ClampedArray,
200    };
201    use wasm_bindgen_test::wasm_bindgen_test;
202
203    macro_rules! gen_integer_tests {
204        ($(($name:ident, $js:ident, $rust:ident),)*) => ($(
205            #[allow(unused)]
206            #[wasm_bindgen_test]
207            fn $name() {
208                let buf1 = vec![1, 2, 3, 4];
209                let array: $js = ArrayBufferCopy::from_slice(&buf1);
210                let buf2 = ArrayBufferCopy::to_vec(&array);
211                assert_eq!(buf1, buf2);
212                let mut buf3 = vec![0; 2];
213                ArrayBufferCopy::copy_to(&array.subarray(0, 2), &mut buf3);
214                assert_eq!(buf3, vec![1, 2]);
215                let buf4 = $js::new_with_length(3);
216                ArrayBufferCopy::copy_from(&buf4.subarray(1, 3), &buf3);
217                assert!(buf4.get_index(0) == 0);
218                assert!(buf4.get_index(1) == 1);
219                assert!(buf4.get_index(2) == 2);
220            }
221        )*);
222    }
223
224    macro_rules! gen_float_tests {
225        ($(($name:ident, $js:ident, $rust:ident),)*) => ($(
226            #[allow(unused)]
227            #[wasm_bindgen_test]
228            fn $name() {
229                let buf1 = vec![1.0, 2.0, 3.0, 4.0];
230                let array: $js = ArrayBufferCopy::from_slice(&buf1);
231                let buf2 = ArrayBufferCopy::to_vec(&array);
232                assert_eq!(buf1, buf2);
233                let mut buf3 = vec![0.0; 2];
234                ArrayBufferCopy::copy_to(&array.subarray(0, 2), &mut buf3);
235                assert_eq!(buf3, vec![1.0, 2.0]);
236                let buf4 = $js::new_with_length(3);
237                ArrayBufferCopy::copy_from(&buf4.subarray(1, 3), &buf3);
238                assert!(buf4.get_index(0) == 0.0);
239                assert!(buf4.get_index(1) == 1.0);
240                assert!(buf4.get_index(2) == 2.0);
241            }
242        )*);
243    }
244
245    gen_integer_tests! {
246        (test_i8, Int8Array, i8),
247        (test_i16, Int16Array, i16),
248        (test_i32, Int32Array, i32),
249        (test_u8, Uint8Array, u8),
250        (test_u8c, Uint8ClampedArray, u8),
251        (test_u16, Uint16Array, u16),
252        (test_u32, Uint32Array, u32),
253        (test_i64, BigInt64Array, i64),
254        (test_u64, BigUint64Array, u64),
255    }
256
257    gen_float_tests! {
258        (test_f32, Float32Array, f32),
259        (test_f64, Float64Array, f64),
260    }
261}