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
99pub trait ArrayBufferCopy<T> {
101 fn from_slice(src: &[T]) -> Self;
103 fn copy_from(&self, src: &[T]);
105 fn copy_to(&self, dst: &mut [T]);
107 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: i8, JSArrayBufferCopy::to_i8_slice, JSArrayBufferCopy::to_i8_array),
150
151 (Int16Array: i16, JSArrayBufferCopy::to_i16_slice, JSArrayBufferCopy::to_i16_array),
154
155 (Int32Array: i32, JSArrayBufferCopy::to_i32_slice, JSArrayBufferCopy::to_i32_array),
158
159 (Uint8Array: u8, JSArrayBufferCopy::to_u8_slice, JSArrayBufferCopy::to_u8_array),
162
163 (Uint8ClampedArray: u8, JSArrayBufferCopy::to_u8c_slice, JSArrayBufferCopy::to_u8c_array),
166
167 (Uint16Array: u16, JSArrayBufferCopy::to_u16_slice, JSArrayBufferCopy::to_u16_array),
170
171 (Uint32Array: u32, JSArrayBufferCopy::to_u32_slice, JSArrayBufferCopy::to_u32_array),
174
175 (Float32Array: f32, JSArrayBufferCopy::to_f32_slice, JSArrayBufferCopy::to_f32_array),
178
179 (Float64Array: f64, JSArrayBufferCopy::to_f64_slice, JSArrayBufferCopy::to_f64_array),
182
183 (BigInt64Array: i64, JSArrayBufferCopy::to_big_i64_slice, JSArrayBufferCopy::to_big_i64_array),
186
187 (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}