Skip to main content

luminance_webgl/webgl2/
array_buffer.rs

1//! A collection of utilities used to perform conversion between immutable slices and JavaScript’s
2//! various array types.
3
4/// Unsafe coercion to a `js_sys::Object` for immutable slices.
5///
6/// This trait provides the [`into_array_buffer`] method, which is an unsafe operation, as
7/// the `view()` method, defined on the various arrays in the `js-sys` crate, requires that the
8/// underlying memory not be moved until the array is dropped.
9///
10/// [`into_array_buffer`]: crate::webgl2::array_buffer::IntoArrayBuffer::into_array_buffer
11pub trait IntoArrayBuffer: Sized {
12  /// Convert the input slice into a JavaScript object.
13  ///
14  /// # Unsafety
15  ///
16  /// The returned `Object` must not outlive the input slice, which memory must not be moved either.
17  unsafe fn into_array_buffer(texels: &[Self]) -> js_sys::Object;
18}
19
20macro_rules! impl_IntoArrayBuffer {
21  ($t:ty, $buffer:ty) => {
22    impl IntoArrayBuffer for $t {
23      unsafe fn into_array_buffer(texels: &[Self]) -> js_sys::Object {
24        <$buffer>::view(texels).into()
25      }
26    }
27
28    impl_tuple_IntoArrayBuffer!($t, ($t, $t), 2, $buffer);
29    impl_tuple_IntoArrayBuffer!($t, ($t, $t, $t), 3, $buffer);
30    impl_tuple_IntoArrayBuffer!($t, ($t, $t, $t, $t), 4, $buffer);
31
32    impl_array_IntoArrayBuffer!($t, $buffer);
33  };
34}
35
36macro_rules! impl_tuple_IntoArrayBuffer {
37  ($t:ty, $tuple:ty, $n:literal, $buffer:ty) => {
38    // statically assert that [T; 3] has the same size as (T, T, T)
39    // this checks that the from_raw_parts cast has the correct value for $n and $tuple
40    const _: fn() = || {
41      let _ = std::mem::transmute::<[$t; $n], $tuple>;
42    };
43
44    impl IntoArrayBuffer for $tuple {
45      unsafe fn into_array_buffer(texels: &[Self]) -> js_sys::Object {
46        let slice: &[$t] =
47          std::slice::from_raw_parts(texels.as_ptr() as *const $t, texels.len() * $n);
48
49        <$buffer>::view(slice).into()
50      }
51    }
52  };
53}
54
55macro_rules! impl_array_IntoArrayBuffer {
56  ($t:ty, $buffer:ty) => {
57    impl<const N: usize> IntoArrayBuffer for [$t; N] {
58      unsafe fn into_array_buffer(texels: &[Self]) -> js_sys::Object {
59        let slice: &[$t] =
60          std::slice::from_raw_parts(texels.as_ptr() as *const $t, texels.len() * N);
61
62        <$buffer>::view(slice).into()
63      }
64    }
65  };
66}
67
68impl_IntoArrayBuffer!(u8, js_sys::Uint8Array);
69impl_IntoArrayBuffer!(i8, js_sys::Int8Array);
70impl_IntoArrayBuffer!(u16, js_sys::Uint16Array);
71impl_IntoArrayBuffer!(i16, js_sys::Int16Array);
72impl_IntoArrayBuffer!(u32, js_sys::Uint32Array);
73impl_IntoArrayBuffer!(i32, js_sys::Int32Array);
74
75impl_IntoArrayBuffer!(f32, js_sys::Float32Array);
76impl_IntoArrayBuffer!(f64, js_sys::Float64Array);