ul_next/javascript/
typed_array.rs

1use std::ops::Deref;
2
3use super::{AsJSValue, JSContext, JSValue};
4
5/// An enum identifying the Typed Array type of a [`JSTypedArray`].
6#[repr(u32)]
7#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
8pub enum JSTypedArrayType {
9    Int8Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt8Array,
10    Int16Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt16Array,
11    Int32Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt32Array,
12    Uint8Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint8Array,
13    Uint8ClampedArray = ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint8ClampedArray,
14    Uint16Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint16Array,
15    Uint32Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint32Array,
16    Float32Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeFloat32Array,
17    Float64Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeFloat64Array,
18    ArrayBuffer = ul_sys::JSTypedArrayType_kJSTypedArrayTypeArrayBuffer,
19    None = ul_sys::JSTypedArrayType_kJSTypedArrayTypeNone,
20    BigInt64Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeBigInt64Array,
21    BigUint64Array = ul_sys::JSTypedArrayType_kJSTypedArrayTypeBigUint64Array,
22}
23
24/// A JavaScript Typed Array object.
25#[derive(Clone, Debug)]
26pub struct JSTypedArray<'a> {
27    pub(crate) value: JSValue<'a>,
28}
29
30impl<'a> JSTypedArray<'a> {
31    /// Creates a Javascript Typed Array object with the given number of elements
32    /// all initialized to zero.
33    ///
34    /// Returns [`Err`] if an exception occurred while creating the object.
35    pub fn new(
36        ctx: &'a JSContext,
37        array_type: JSTypedArrayType,
38        length: usize,
39    ) -> Result<Self, JSValue<'a>> {
40        let mut exception = std::ptr::null();
41        let value = unsafe {
42            ctx.lib.ultralight().JSObjectMakeTypedArray(
43                ctx.internal,
44                array_type as _,
45                length,
46                &mut exception,
47            )
48        };
49
50        if !exception.is_null() {
51            Err(JSValue::from_raw(ctx, exception))
52        } else if value.is_null() {
53            return Err(JSValue::new_string(ctx, "Failed to create typed array"));
54        } else {
55            Ok(Self {
56                value: JSValue::from_raw(ctx, value),
57            })
58        }
59    }
60
61    /// Creates a JavaScript Typed Array object from existing bytes buffer.
62    ///
63    /// This will copy the bytes and manages its memory.
64    ///
65    /// Returns [`Err`] if an exception occurred while creating the object.
66    pub fn new_copy_from_bytes(
67        ctx: &'a JSContext,
68        array_type: JSTypedArrayType,
69        bytes: &[u8],
70    ) -> Result<Self, JSValue<'a>> {
71        extern "C" fn deallocator(
72            bytes: *mut std::ffi::c_void,
73            deallocator_context: *mut std::ffi::c_void,
74        ) {
75            let slice_size = deallocator_context as usize;
76
77            drop(unsafe {
78                Box::from_raw(std::slice::from_raw_parts_mut(bytes as *mut u8, slice_size))
79            })
80        }
81
82        let mut exception = std::ptr::null();
83        let boxed_bytes = Vec::from(bytes).into_boxed_slice();
84
85        let date_size = boxed_bytes.len();
86        let data = Box::into_raw(boxed_bytes);
87
88        let value = unsafe {
89            ctx.lib.ultralight().JSObjectMakeTypedArrayWithBytesNoCopy(
90                ctx.internal,
91                array_type as _,
92                data as _,
93                bytes.len(),
94                Some(deallocator),
95                date_size as _,
96                &mut exception,
97            )
98        };
99
100        if !exception.is_null() {
101            Err(JSValue::from_raw(ctx, exception))
102        } else if value.is_null() {
103            return Err(JSValue::new_string(ctx, "Failed to create typed array"));
104        } else {
105            Ok(Self {
106                value: JSValue::from_raw(ctx, value),
107            })
108        }
109    }
110
111    /// Returns the length of a JavaScript Typed Array object.
112    ///
113    /// Returns [`Err`] if an exception occurred while getting the length.
114    pub fn len(&self) -> Result<usize, JSValue<'a>> {
115        let mut exception = std::ptr::null();
116
117        let result = unsafe {
118            self.value.ctx.lib.ultralight().JSObjectGetTypedArrayLength(
119                self.value.ctx.internal,
120                self.value.internal as _,
121                &mut exception,
122            )
123        };
124
125        if !exception.is_null() {
126            Err(JSValue::from_raw(self.value.ctx, exception))
127        } else {
128            Ok(result)
129        }
130    }
131
132    /// Returns whether the JavaScript Typed Array object is empty.
133    ///
134    /// Returns [`Err`] if an exception occurred while getting the length.
135    pub fn is_empty(&self) -> Result<bool, JSValue<'a>> {
136        self.len().map(|len| len == 0)
137    }
138
139    /// Returns the byte length of a JavaScript Typed Array object.
140    ///
141    /// Returns [`Err`] if an exception occurred while getting the byte length.
142    pub fn byte_length(&self) -> Result<usize, JSValue<'a>> {
143        let mut exception = std::ptr::null();
144
145        let result = unsafe {
146            self.value
147                .ctx
148                .lib
149                .ultralight()
150                .JSObjectGetTypedArrayByteLength(
151                    self.value.ctx.internal,
152                    self.value.internal as _,
153                    &mut exception,
154                )
155        };
156
157        if !exception.is_null() {
158            Err(JSValue::from_raw(self.value.ctx, exception))
159        } else {
160            Ok(result)
161        }
162    }
163
164    /// Returns the byte offset of a JavaScript Typed Array object.
165    ///
166    /// Returns [`Err`] if an exception occurred while getting the byte offset.
167    pub fn byte_offset(&self) -> Result<usize, JSValue<'a>> {
168        let mut exception = std::ptr::null();
169
170        let result = unsafe {
171            self.value
172                .ctx
173                .lib
174                .ultralight()
175                .JSObjectGetTypedArrayByteOffset(
176                    self.value.ctx.internal,
177                    self.value.internal as _,
178                    &mut exception,
179                )
180        };
181
182        if !exception.is_null() {
183            Err(JSValue::from_raw(self.value.ctx, exception))
184        } else {
185            Ok(result)
186        }
187    }
188
189    /// Returns the type of a JavaScript Typed Array object.
190    ///
191    /// Returns [`Err`] if an exception occurred while getting the type,
192    /// or [`JSTypedArrayType::None`] if object isn't a Typed Array.
193    pub fn ty(&self) -> Result<JSTypedArrayType, JSValue<'a>> {
194        let mut exception = std::ptr::null();
195
196        let ty = unsafe {
197            self.value.ctx.lib.ultralight().JSValueGetTypedArrayType(
198                self.value.ctx.internal,
199                self.value.internal as _,
200                &mut exception,
201            )
202        };
203
204        if !exception.is_null() {
205            Err(JSValue::from_raw(self.value.ctx, exception))
206        } else {
207            match ty {
208                ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt8Array => {
209                    Ok(JSTypedArrayType::Int8Array)
210                }
211                ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt16Array => {
212                    Ok(JSTypedArrayType::Int16Array)
213                }
214                ul_sys::JSTypedArrayType_kJSTypedArrayTypeInt32Array => {
215                    Ok(JSTypedArrayType::Int32Array)
216                }
217                ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint8Array => {
218                    Ok(JSTypedArrayType::Uint8Array)
219                }
220                ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint8ClampedArray => {
221                    Ok(JSTypedArrayType::Uint8ClampedArray)
222                }
223                ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint16Array => {
224                    Ok(JSTypedArrayType::Uint16Array)
225                }
226                ul_sys::JSTypedArrayType_kJSTypedArrayTypeUint32Array => {
227                    Ok(JSTypedArrayType::Uint32Array)
228                }
229                ul_sys::JSTypedArrayType_kJSTypedArrayTypeFloat32Array => {
230                    Ok(JSTypedArrayType::Float32Array)
231                }
232                ul_sys::JSTypedArrayType_kJSTypedArrayTypeFloat64Array => {
233                    Ok(JSTypedArrayType::Float64Array)
234                }
235                ul_sys::JSTypedArrayType_kJSTypedArrayTypeArrayBuffer => {
236                    Ok(JSTypedArrayType::ArrayBuffer)
237                }
238                ul_sys::JSTypedArrayType_kJSTypedArrayTypeNone => Ok(JSTypedArrayType::None),
239                ul_sys::JSTypedArrayType_kJSTypedArrayTypeBigInt64Array => {
240                    Ok(JSTypedArrayType::BigInt64Array)
241                }
242                ul_sys::JSTypedArrayType_kJSTypedArrayTypeBigUint64Array => {
243                    Ok(JSTypedArrayType::BigUint64Array)
244                }
245                _ => Err(JSValue::new_string(
246                    self.value.ctx,
247                    &format!("Unknown typed array type: {}", ty),
248                )),
249            }
250        }
251    }
252}
253
254impl<'a> AsRef<JSValue<'a>> for JSTypedArray<'a> {
255    fn as_ref(&self) -> &JSValue<'a> {
256        &self.value
257    }
258}
259
260impl<'a> Deref for JSTypedArray<'a> {
261    type Target = JSValue<'a>;
262
263    fn deref(&self) -> &Self::Target {
264        &self.value
265    }
266}
267
268impl<'a> AsJSValue<'a> for JSTypedArray<'a> {
269    fn into_value(self) -> JSValue<'a> {
270        self.value
271    }
272
273    fn as_value(&self) -> &JSValue<'a> {
274        &self.value
275    }
276}