@@ -188,6 +188,68 @@ impl JSValue {
188
188
Ok ( JSValue :: new_inner ( ctx. raw , result) )
189
189
}
190
190
191
+ /// Creates a JavaScript value of the `TypedArray` type.
192
+ ///
193
+ /// * `ctx`: The execution context to use.
194
+ /// * `bytes`: The typed array bytes. The constructed `TypedArray` doesn't copy the bytes,
195
+ /// thus this method takes a `&mut` reference as it is possible to mutate the bytes via
196
+ /// `TypedArray` or via Rust.
197
+ ///
198
+ /// Returns a `JSValue` of the `TypedArray` type, otherwise an exception.
199
+ ///
200
+ /// # Safety
201
+ ///
202
+ /// `bytes` can be mutated both by Rust or JavaScript. There is no lock, no mutex, no
203
+ /// guard. Be extremely careful when using this API. `bytes` aren't copied, they are
204
+ /// borrowed mutably by JavaScript. Dropping the value in Rust will clear them in
205
+ /// JavaScript, and vice versa. Hence, this method is marked as `unsafe`.
206
+ ///
207
+ /// # Example
208
+ ///
209
+ /// ```rust
210
+ /// # use javascriptcore::{JSContext, JSValue};
211
+ /// let ctx = JSContext::default();
212
+ /// let mut bytes = vec![1u8, 2, 3, 4, 5];
213
+ /// let value = unsafe {
214
+ /// JSValue::new_typed_array_with_bytes(&ctx, bytes.as_mut_slice())
215
+ /// .unwrap()
216
+ /// };
217
+ /// ```
218
+ pub unsafe fn new_typed_array_with_bytes (
219
+ ctx : & JSContext ,
220
+ // `&mut` instead of &` because the typed array borrows mutably the bytes.
221
+ //
222
+ // The argument is named `_bytes` instead of `bytes` to avoid a
223
+ // `clippy::needless_pass_by_ref_mut` warning (only on Rust nightly).
224
+ _bytes : & mut [ u8 ] ,
225
+ ) -> Result < Self , JSException > {
226
+ let bytes = _bytes;
227
+ let deallocator_ctx = ptr:: null_mut ( ) ;
228
+ let mut exception: sys:: JSValueRef = ptr:: null_mut ( ) ;
229
+
230
+ let result = unsafe {
231
+ sys:: JSObjectMakeTypedArrayWithBytesNoCopy (
232
+ ctx. raw ,
233
+ sys:: JSTypedArrayType :: Uint8Array ,
234
+ bytes. as_ptr ( ) as _ ,
235
+ bytes. len ( ) ,
236
+ None ,
237
+ deallocator_ctx,
238
+ & mut exception,
239
+ )
240
+ } ;
241
+
242
+ if !exception. is_null ( ) {
243
+ return Err ( JSValue :: new_inner ( ctx. raw , exception) . into ( ) ) ;
244
+ }
245
+
246
+ if result. is_null ( ) {
247
+ return Err ( JSValue :: new_string ( ctx, "Failed to make a new typed array" ) . into ( ) ) ;
248
+ }
249
+
250
+ Ok ( JSValue :: new_inner ( ctx. raw , result) )
251
+ }
252
+
191
253
/// Creates a JavaScript value from a JSON formatted string.
192
254
///
193
255
/// * `ctx`: The execution context to use.
@@ -650,6 +712,57 @@ mod tests {
650
712
assert ! ( !vo. get_property_at_index( 1 ) . as_boolean( ) ) ;
651
713
}
652
714
715
+ #[ test]
716
+ fn typed_array ( ) {
717
+ let ctx = JSContext :: default ( ) ;
718
+ let mut bytes = vec ! [ 1u8 , 2 , 3 , 4 , 5 ] ;
719
+ let array = unsafe { JSValue :: new_typed_array_with_bytes ( & ctx, bytes. as_mut_slice ( ) ) }
720
+ . unwrap ( )
721
+ . as_object ( )
722
+ . unwrap ( ) ;
723
+
724
+ assert_eq ! (
725
+ unsafe {
726
+ array
727
+ . get_property( "byteLength" )
728
+ . as_number( )
729
+ . unwrap( )
730
+ . to_int_unchecked:: <usize >( )
731
+ } ,
732
+ bytes. len( )
733
+ ) ;
734
+ assert_eq ! (
735
+ unsafe {
736
+ array
737
+ . get_property( "BYTES_PER_ELEMENT" )
738
+ . as_number( )
739
+ . unwrap( )
740
+ . to_int_unchecked:: <usize >( )
741
+ } ,
742
+ 1
743
+ ) ;
744
+
745
+ // Let's test the mutability of the bytes, i.e. they aren't copied but borrowed.
746
+ array
747
+ . set_property_at_index ( 2 , JSValue :: new_number ( & ctx, 10. ) )
748
+ . unwrap ( ) ;
749
+
750
+ assert_eq ! ( bytes, & [ 1u8 , 2 , 10 , 4 , 5 ] ) ;
751
+
752
+ bytes[ 3 ] = 11 ;
753
+
754
+ assert_eq ! (
755
+ unsafe {
756
+ array
757
+ . get_property_at_index( 3 )
758
+ . as_number( )
759
+ . unwrap( )
760
+ . to_int_unchecked:: <u8 >( )
761
+ } ,
762
+ 11
763
+ )
764
+ }
765
+
653
766
#[ test]
654
767
fn json_boolean_true ( ) {
655
768
let ctx = JSContext :: default ( ) ;
0 commit comments