1use std::ffi::{c_void, CString};
2use std::ptr;
3use std::result;
4use std::slice;
5use std::string;
6
7pub use bare_rust_ffi as ffi;
8
9use ffi::*;
10
11macro_rules! assert_status {
12    ($status:expr, $message:expr) => {
13        assert!($status == 0, $message);
14    };
15}
16
17macro_rules! check_status {
18    ($env:expr, $status:expr) => {
19        if $status == JS_PENDING_EXCEPTION {
20            return Err($env.pending_exception());
21        } else {
22            assert_status!($status, "Uncaught JavaScript exception");
23        }
24    };
25}
26
27type Result<T> = result::Result<T, Value>;
28
29#[derive(Debug)]
30pub struct Env {
31    ptr: *mut js_env_t,
32}
33
34impl Env {
35    pub fn is_exception_pending(&self) -> bool {
36        let mut result = false;
37
38        unsafe {
39            js_is_exception_pending(self.ptr, &mut result);
40        }
41
42        result
43    }
44
45    pub fn pending_exception(&self) -> Value {
46        let mut ptr: *mut js_value_t = ptr::null_mut();
47
48        unsafe {
49            js_get_and_clear_last_exception(self.ptr, &mut ptr);
50        }
51
52        Value { env: self.ptr, ptr }
53    }
54}
55
56impl From<*mut js_env_t> for Env {
57    fn from(ptr: *mut js_env_t) -> Self {
58        Self { ptr }
59    }
60}
61
62#[derive(Debug)]
63pub struct Scope {
64    env: *mut js_env_t,
65    ptr: *mut js_handle_scope_t,
66}
67
68impl Scope {
69    pub fn new(env: &Env) -> Self {
70        let mut ptr: *mut js_handle_scope_t = ptr::null_mut();
71
72        unsafe {
73            js_open_handle_scope(env.ptr, &mut ptr);
74        }
75
76        Self { env: env.ptr, ptr }
77    }
78}
79
80impl Drop for Scope {
81    fn drop(&mut self) {
82        unsafe {
83            js_close_handle_scope(self.env, self.ptr);
84        }
85    }
86}
87
88#[derive(Debug)]
89pub struct EscapableScope {
90    env: *mut js_env_t,
91    ptr: *mut js_escapable_handle_scope_t,
92}
93
94impl EscapableScope {
95    pub fn new(env: &Env) -> Self {
96        let mut ptr: *mut js_escapable_handle_scope_t = ptr::null_mut();
97
98        unsafe {
99            js_open_escapable_handle_scope(env.ptr, &mut ptr);
100        }
101
102        Self { env: env.ptr, ptr }
103    }
104
105    pub fn escape<T>(self, escapee: T) -> Value
106    where
107        T: Into<Value>,
108    {
109        let mut ptr: *mut js_value_t = ptr::null_mut();
110
111        unsafe {
112            js_escape_handle(self.env, self.ptr, escapee.into().ptr, &mut ptr);
113        }
114
115        Value { env: self.env, ptr }
116    }
117}
118
119impl Drop for EscapableScope {
120    fn drop(&mut self) {
121        unsafe {
122            js_close_escapable_handle_scope(self.env, self.ptr);
123        }
124    }
125}
126
127#[derive(Debug)]
128pub struct Ref {
129    env: *mut js_env_t,
130    ptr: *mut js_ref_t,
131}
132
133impl Ref {
134    pub fn new<T>(env: &Env, value: T) -> Self
135    where
136        T: Into<Value>,
137    {
138        let mut ptr: *mut js_ref_t = ptr::null_mut();
139
140        unsafe {
141            js_create_reference(env.ptr, value.into().ptr, 1, &mut ptr);
142        }
143
144        Ref { env: env.ptr, ptr }
145    }
146
147    pub fn get<T>(&self) -> T
148    where
149        T: From<Value>,
150    {
151        let mut ptr: *mut js_value_t = ptr::null_mut();
152
153        unsafe {
154            js_get_reference_value(self.env, self.ptr, &mut ptr);
155        }
156
157        Value { env: self.env, ptr }.into()
158    }
159}
160
161impl Drop for Ref {
162    fn drop(&mut self) {
163        unsafe {
164            js_delete_reference(self.env, self.ptr);
165        }
166    }
167}
168
169impl From<Ref> for Value {
170    fn from(reference: Ref) -> Self {
171        reference.get()
172    }
173}
174
175#[derive(Debug)]
176pub struct WeakRef {
177    env: *mut js_env_t,
178    ptr: *mut js_ref_t,
179}
180
181impl WeakRef {
182    pub fn new<T>(env: &Env, value: T) -> Self
183    where
184        T: Into<Value>,
185    {
186        let mut ptr: *mut js_ref_t = ptr::null_mut();
187
188        unsafe {
189            js_create_reference(env.ptr, value.into().ptr, 0, &mut ptr);
190        }
191
192        WeakRef { env: env.ptr, ptr }
193    }
194
195    pub fn get<T>(&self) -> Option<T>
196    where
197        T: From<Value>,
198    {
199        let mut ptr: *mut js_value_t = ptr::null_mut();
200
201        unsafe {
202            js_get_reference_value(self.env, self.ptr, &mut ptr);
203        }
204
205        if ptr.is_null() {
206            None
207        } else {
208            Some(Value { env: self.env, ptr }.into())
209        }
210    }
211}
212
213impl Drop for WeakRef {
214    fn drop(&mut self) {
215        unsafe {
216            js_delete_reference(self.env, self.ptr);
217        }
218    }
219}
220
221#[derive(Debug)]
222pub struct Value {
223    env: *mut js_env_t,
224    ptr: *mut js_value_t,
225}
226
227impl From<Value> for *mut js_value_t {
228    fn from(value: Value) -> Self {
229        value.ptr
230    }
231}
232
233macro_rules! value_conversions {
234    ($type: ident) => {
235        impl From<$type> for *mut js_value_t {
236            fn from(value: $type) -> Self {
237                value.0.ptr
238            }
239        }
240
241        impl From<$type> for Value {
242            fn from(value: $type) -> Self {
243                value.0
244            }
245        }
246
247        impl From<Value> for $type {
248            fn from(value: Value) -> Self {
249                Self(value)
250            }
251        }
252    };
253}
254
255#[derive(Debug)]
256pub struct Undefined(Value);
257
258impl Undefined {
259    pub fn new(env: &Env) -> Self {
260        let mut ptr: *mut js_value_t = ptr::null_mut();
261
262        unsafe {
263            js_get_undefined(env.ptr, &mut ptr);
264        }
265
266        Self(Value { env: env.ptr, ptr })
267    }
268}
269
270value_conversions!(Undefined);
271
272#[derive(Debug)]
273pub struct Null(Value);
274
275impl Null {
276    pub fn new(env: &Env) -> Self {
277        let mut ptr: *mut js_value_t = ptr::null_mut();
278
279        unsafe {
280            js_get_null(env.ptr, &mut ptr);
281        }
282
283        Self(Value { env: env.ptr, ptr })
284    }
285}
286
287value_conversions!(Null);
288
289#[derive(Debug)]
290pub struct Boolean(Value);
291
292impl Boolean {
293    pub fn new(env: &Env, value: bool) -> Self {
294        let mut ptr: *mut js_value_t = ptr::null_mut();
295
296        unsafe {
297            js_get_boolean(env.ptr, value, &mut ptr);
298        }
299
300        Self(Value { env: env.ptr, ptr })
301    }
302}
303
304value_conversions!(Boolean);
305
306impl From<Boolean> for bool {
307    fn from(boolean: Boolean) -> Self {
308        let mut value = false;
309
310        unsafe {
311            js_get_value_bool(boolean.0.env, boolean.0.ptr, &mut value);
312        }
313
314        value
315    }
316}
317
318#[derive(Debug)]
319pub struct Number(Value);
320
321impl Number {
322    pub fn with_i32(env: &Env, value: i32) -> Self {
323        let mut ptr: *mut js_value_t = ptr::null_mut();
324
325        unsafe {
326            js_create_int32(env.ptr, value, &mut ptr);
327        }
328
329        Self(Value { env: env.ptr, ptr })
330    }
331
332    pub fn with_u32(env: &Env, value: u32) -> Self {
333        let mut ptr: *mut js_value_t = ptr::null_mut();
334
335        unsafe {
336            js_create_uint32(env.ptr, value, &mut ptr);
337        }
338
339        Self(Value { env: env.ptr, ptr })
340    }
341
342    pub fn with_i64(env: &Env, value: i64) -> Self {
343        let mut ptr: *mut js_value_t = ptr::null_mut();
344
345        unsafe {
346            js_create_int64(env.ptr, value, &mut ptr);
347        }
348
349        Self(Value { env: env.ptr, ptr })
350    }
351
352    pub fn with_f64(env: &Env, value: f64) -> Self {
353        let mut ptr: *mut js_value_t = ptr::null_mut();
354
355        unsafe {
356            js_create_double(env.ptr, value, &mut ptr);
357        }
358
359        Self(Value { env: env.ptr, ptr })
360    }
361}
362
363value_conversions!(Number);
364
365impl From<Number> for i32 {
366    fn from(number: Number) -> Self {
367        let mut value = 0;
368
369        unsafe {
370            js_get_value_int32(number.0.env, number.0.ptr, &mut value);
371        }
372
373        value
374    }
375}
376
377impl From<Number> for u32 {
378    fn from(number: Number) -> Self {
379        let mut value = 0;
380
381        unsafe {
382            js_get_value_uint32(number.0.env, number.0.ptr, &mut value);
383        }
384
385        value
386    }
387}
388
389impl From<Number> for i64 {
390    fn from(number: Number) -> Self {
391        let mut value = 0;
392
393        unsafe {
394            js_get_value_int64(number.0.env, number.0.ptr, &mut value);
395        }
396
397        value
398    }
399}
400
401impl From<Number> for f64 {
402    fn from(number: Number) -> Self {
403        let mut value = 0.0;
404
405        unsafe {
406            js_get_value_double(number.0.env, number.0.ptr, &mut value);
407        }
408
409        value
410    }
411}
412
413#[derive(Debug)]
414pub struct BigInt(Value);
415
416impl BigInt {
417    pub fn with_i64(env: &Env, value: i64) -> Self {
418        let mut ptr: *mut js_value_t = ptr::null_mut();
419
420        unsafe {
421            js_create_bigint_int64(env.ptr, value, &mut ptr);
422        }
423
424        Self(Value { env: env.ptr, ptr })
425    }
426
427    pub fn with_u64(env: &Env, value: u64) -> Self {
428        let mut ptr: *mut js_value_t = ptr::null_mut();
429
430        unsafe {
431            js_create_bigint_uint64(env.ptr, value, &mut ptr);
432        }
433
434        Self(Value { env: env.ptr, ptr })
435    }
436}
437
438value_conversions!(BigInt);
439
440impl From<BigInt> for i64 {
441    fn from(bigint: BigInt) -> Self {
442        let mut value = 0;
443
444        unsafe {
445            js_get_value_bigint_int64(bigint.0.env, bigint.0.ptr, &mut value, ptr::null_mut());
446        }
447
448        value
449    }
450}
451
452impl From<BigInt> for u64 {
453    fn from(bigint: BigInt) -> Self {
454        let mut value = 0;
455
456        unsafe {
457            js_get_value_bigint_uint64(bigint.0.env, bigint.0.ptr, &mut value, ptr::null_mut());
458        }
459
460        value
461    }
462}
463
464#[derive(Debug)]
465pub struct Name(Value);
466
467value_conversions!(Name);
468
469impl From<String> for Name {
470    fn from(string: String) -> Self {
471        Name(string.0)
472    }
473}
474
475impl From<Symbol> for Name {
476    fn from(symbol: Symbol) -> Self {
477        Name(symbol.0)
478    }
479}
480
481#[derive(Debug)]
482pub struct Symbol(Value);
483
484impl Symbol {
485    pub fn new(env: &Env, description: &str) -> Result<Self> {
486        let description = String::new(env, description)?;
487
488        let mut ptr: *mut js_value_t = ptr::null_mut();
489
490        let status = unsafe { js_create_symbol(env.ptr, description.0.ptr, &mut ptr) };
491
492        check_status!(env, status);
493
494        Ok(Self(Value { env: env.ptr, ptr }))
495    }
496}
497
498value_conversions!(Symbol);
499
500#[derive(Debug)]
501pub struct String(Value);
502
503impl String {
504    pub fn new(env: &Env, value: &str) -> Result<Self> {
505        let mut ptr: *mut js_value_t = ptr::null_mut();
506
507        let status = unsafe {
508            js_create_string_utf8(
509                env.ptr,
510                value.as_ptr().cast(),
511                value.len() as usize,
512                &mut ptr,
513            )
514        };
515
516        check_status!(env, status);
517
518        Ok(Self(Value { env: env.ptr, ptr }))
519    }
520
521    pub fn to_bytes(&self) -> Vec<u8> {
522        let mut len = 0;
523
524        unsafe {
525            js_get_value_string_utf8(self.0.env, self.0.ptr, ptr::null_mut(), 0, &mut len);
526        }
527
528        let mut result = Vec::new();
529
530        result.resize(len, 0);
531
532        unsafe {
533            js_get_value_string_utf8(self.0.env, self.0.ptr, result.as_mut_ptr(), len, &mut len);
534        }
535
536        result
537    }
538}
539
540value_conversions!(String);
541
542impl From<String> for string::String {
543    fn from(string: String) -> Self {
544        unsafe { string::String::from_utf8_unchecked(string.to_bytes()) }
545    }
546}
547
548#[derive(Debug)]
549pub struct Object(Value);
550
551impl Object {
552    pub fn new(env: &Env) -> Result<Self> {
553        let mut ptr: *mut js_value_t = ptr::null_mut();
554
555        let status = unsafe { js_create_object(env.ptr, &mut ptr) };
556
557        check_status!(env, status);
558
559        Ok(Self(Value { env: env.ptr, ptr }))
560    }
561
562    pub fn get_property<N, T>(&self, name: N) -> Result<T>
563    where
564        N: Into<Name>,
565        T: From<Value>,
566    {
567        let env = Env::from(self.0.env);
568
569        let mut ptr: *mut js_value_t = ptr::null_mut();
570
571        let status =
572            unsafe { js_get_property(self.0.env, self.0.ptr, name.into().0.ptr, &mut ptr) };
573
574        check_status!(env, status);
575
576        Ok(Value { env: env.ptr, ptr }.into())
577    }
578
579    pub fn get_named_property<T>(&self, name: &str) -> Result<T>
580    where
581        T: From<Value>,
582    {
583        let env = Env::from(self.0.env);
584
585        let key = CString::new(name).unwrap();
586
587        let mut ptr: *mut js_value_t = ptr::null_mut();
588
589        let status =
590            unsafe { js_get_named_property(self.0.env, self.0.ptr, key.as_ptr(), &mut ptr) };
591
592        check_status!(env, status);
593
594        Ok(Value { env: env.ptr, ptr }.into())
595    }
596
597    pub fn get_element<T>(&self, index: u32) -> Result<T>
598    where
599        T: From<Value>,
600    {
601        let env = Env::from(self.0.env);
602
603        let mut ptr: *mut js_value_t = ptr::null_mut();
604
605        let status = unsafe { js_get_element(self.0.env, self.0.ptr, index, &mut ptr) };
606
607        check_status!(env, status);
608
609        Ok(Value { env: env.ptr, ptr }.into())
610    }
611
612    pub fn has_property<N>(&self, name: N) -> Result<bool>
613    where
614        N: Into<Name>,
615    {
616        let env = Env::from(self.0.env);
617
618        let mut result = false;
619
620        let status =
621            unsafe { js_has_property(self.0.env, self.0.ptr, name.into().0.ptr, &mut result) };
622
623        check_status!(env, status);
624
625        Ok(result)
626    }
627
628    pub fn has_own_property<N>(&self, name: N) -> Result<bool>
629    where
630        N: Into<Name>,
631    {
632        let env = Env::from(self.0.env);
633
634        let mut result = false;
635
636        let status =
637            unsafe { js_has_own_property(self.0.env, self.0.ptr, name.into().0.ptr, &mut result) };
638
639        check_status!(env, status);
640
641        Ok(result)
642    }
643
644    pub fn has_named_property(&self, name: &str) -> Result<bool> {
645        let env = Env::from(self.0.env);
646
647        let key = CString::new(name).unwrap();
648
649        let mut result = false;
650
651        let status =
652            unsafe { js_has_named_property(self.0.env, self.0.ptr, key.as_ptr(), &mut result) };
653
654        check_status!(env, status);
655
656        Ok(result)
657    }
658
659    pub fn has_element(&self, index: u32) -> Result<bool> {
660        let env = Env::from(self.0.env);
661
662        let mut result = false;
663
664        let status = unsafe { js_has_element(self.0.env, self.0.ptr, index, &mut result) };
665
666        check_status!(env, status);
667
668        Ok(result)
669    }
670
671    pub fn set_property<N, T>(&mut self, name: N, value: T) -> Result<()>
672    where
673        N: Into<Name>,
674        T: Into<Value>,
675    {
676        let env = Env::from(self.0.env);
677
678        let status =
679            unsafe { js_set_property(self.0.env, self.0.ptr, name.into().0.ptr, value.into().ptr) };
680
681        check_status!(env, status);
682
683        Ok(())
684    }
685
686    pub fn set_named_property<T>(&mut self, name: &str, value: T) -> Result<()>
687    where
688        T: Into<Value>,
689    {
690        let env = Env::from(self.0.env);
691
692        let key = CString::new(name).unwrap();
693
694        let status = unsafe {
695            js_set_named_property(self.0.env, self.0.ptr, key.as_ptr(), value.into().ptr)
696        };
697
698        check_status!(env, status);
699
700        Ok(())
701    }
702
703    pub fn set_element<T>(&mut self, index: u32, value: T) -> Result<()>
704    where
705        T: Into<Value>,
706    {
707        let env = Env::from(self.0.env);
708
709        let status = unsafe { js_set_element(self.0.env, self.0.ptr, index, value.into().ptr) };
710
711        check_status!(env, status);
712
713        Ok(())
714    }
715
716    pub fn delete_property<N>(&self, name: N) -> Result<bool>
717    where
718        N: Into<Name>,
719    {
720        let env = Env::from(self.0.env);
721
722        let mut result = false;
723
724        let status =
725            unsafe { js_delete_property(self.0.env, self.0.ptr, name.into().0.ptr, &mut result) };
726
727        check_status!(env, status);
728
729        Ok(result)
730    }
731
732    pub fn delete_named_property(&self, name: &str) -> Result<bool> {
733        let env = Env::from(self.0.env);
734
735        let key = CString::new(name).unwrap();
736
737        let mut result = false;
738
739        let status =
740            unsafe { js_delete_named_property(self.0.env, self.0.ptr, key.as_ptr(), &mut result) };
741
742        check_status!(env, status);
743
744        Ok(result)
745    }
746
747    pub fn delete_element(&self, index: u32) -> Result<bool> {
748        let env = Env::from(self.0.env);
749
750        let mut result = false;
751
752        let status = unsafe { js_delete_element(self.0.env, self.0.ptr, index, &mut result) };
753
754        check_status!(env, status);
755
756        Ok(result)
757    }
758}
759
760value_conversions!(Object);
761
762#[derive(Debug)]
763pub struct Array(Value);
764
765impl Array {
766    pub fn new(env: &Env, len: usize) -> Result<Self> {
767        let mut ptr: *mut js_value_t = ptr::null_mut();
768
769        let status = unsafe { js_create_array_with_length(env.ptr, len, &mut ptr) };
770
771        check_status!(env, status);
772
773        Ok(Self(Value { env: env.ptr, ptr }))
774    }
775
776    pub fn len(&self) -> u32 {
777        let mut len = 0;
778
779        unsafe {
780            js_get_array_length(self.0.env, self.0.ptr, &mut len);
781        }
782
783        len
784    }
785
786    pub fn get<T>(&self, index: u32) -> Result<T>
787    where
788        T: From<Value>,
789    {
790        let env = Env::from(self.0.env);
791
792        let mut ptr: *mut js_value_t = ptr::null_mut();
793
794        let status = unsafe { js_get_element(self.0.env, self.0.ptr, index, &mut ptr) };
795
796        check_status!(env, status);
797
798        Ok(Value { env: env.ptr, ptr }.into())
799    }
800
801    pub fn set<T>(&mut self, index: u32, value: T) -> Result<()>
802    where
803        T: Into<Value>,
804    {
805        let env = Env::from(self.0.env);
806
807        let status = unsafe { js_set_element(self.0.env, self.0.ptr, index, value.into().ptr) };
808
809        check_status!(env, status);
810
811        Ok(())
812    }
813}
814
815value_conversions!(Array);
816
817#[derive(Debug)]
818pub struct Callback {
819    env: *mut js_env_t,
820    args: Vec<*mut js_value_t>,
821    receiver: *mut js_value_t,
822}
823
824impl Callback {
825    pub fn arg<T>(&self, i: usize) -> Option<T>
826    where
827        T: From<Value>,
828    {
829        if i < self.args.len() {
830            Some(self.arg_unchecked(i))
831        } else {
832            None
833        }
834    }
835
836    pub fn arg_unchecked<T>(&self, i: usize) -> T
837    where
838        T: From<Value>,
839    {
840        Value {
841            env: self.env,
842            ptr: self.args[i],
843        }
844        .into()
845    }
846
847    pub fn receiver<T>(&self) -> T
848    where
849        T: From<Value>,
850    {
851        Value {
852            env: self.env,
853            ptr: self.receiver,
854        }
855        .into()
856    }
857}
858
859#[derive(Debug)]
860pub struct Function(Value);
861
862impl Function {
863    pub fn new<F>(env: &Env, function: F) -> Result<Self>
864    where
865        F: FnMut(&Env, &Callback) -> Result<Value>,
866    {
867        let mut function = function;
868
869        let closure: Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t> =
870            Box::new(move |env, info| match function(env, info) {
871                Ok(result) => result.into(),
872                Err(error) => {
873                    unsafe {
874                        js_throw(env.ptr, error.into());
875                    }
876
877                    ptr::null_mut()
878                }
879            });
880
881        let data = Box::into_raw(Box::new(closure)) as *mut _;
882
883        let mut ptr: *mut js_value_t = ptr::null_mut();
884
885        let status = unsafe {
886            js_create_function(
887                env.ptr,
888                ptr::null_mut(),
889                0,
890                Some(Function::call),
891                data,
892                &mut ptr,
893            )
894        };
895
896        check_status!(env, status);
897
898        unsafe {
899            js_add_finalizer(
900                env.ptr,
901                ptr,
902                data,
903                Some(Function::drop),
904                ptr::null_mut(),
905                ptr::null_mut(),
906            );
907        }
908
909        Ok(Self(Value { env: env.ptr, ptr }))
910    }
911
912    extern "C" fn call(env: *mut js_env_t, info: *mut js_callback_info_t) -> *mut js_value_t {
913        let mut len: usize = 0;
914        let mut receiver: *mut js_value_t = ptr::null_mut();
915        let mut data: *mut c_void = ptr::null_mut();
916
917        unsafe {
918            js_get_callback_info(
919                env,
920                info,
921                &mut len,
922                ptr::null_mut(),
923                &mut receiver,
924                &mut data,
925            );
926        }
927
928        let mut args = Vec::new();
929
930        if len > 0 {
931            args.resize(len, ptr::null_mut());
932
933            unsafe {
934                js_get_callback_info(
935                    env,
936                    info,
937                    &mut len,
938                    args.as_mut_ptr(),
939                    ptr::null_mut(),
940                    ptr::null_mut(),
941                );
942            }
943        }
944
945        let closure =
946            unsafe { &mut *(data as *mut Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t>) };
947
948        closure(
949            &Env::from(env),
950            &Callback {
951                env,
952                args,
953                receiver,
954            },
955        )
956    }
957
958    extern "C" fn drop(_: *mut js_env_t, data: *mut c_void, _: *mut c_void) -> () {
959        unsafe {
960            drop(Box::from_raw(data));
961        }
962    }
963}
964
965value_conversions!(Function);
966
967#[derive(Debug)]
968pub struct External(Value);
969
970impl External {
971    pub fn new<T>(env: &Env, value: T) -> Result<Self> {
972        let data = Box::into_raw(Box::new(value)) as *mut _;
973
974        let mut ptr: *mut js_value_t = ptr::null_mut();
975
976        let status = unsafe {
977            js_create_external(
978                env.ptr,
979                data,
980                Some(External::drop),
981                ptr::null_mut(),
982                &mut ptr,
983            )
984        };
985
986        check_status!(env, status);
987
988        Ok(Self(Value { env: env.ptr, ptr }))
989    }
990
991    pub fn get<T>(&self) -> *mut T {
992        let mut ptr: *mut c_void = ptr::null_mut();
993
994        unsafe {
995            js_get_value_external(self.0.env, self.0.ptr, &mut ptr);
996        }
997
998        ptr as *mut T
999    }
1000
1001    extern "C" fn drop(_: *mut js_env_t, data: *mut c_void, _: *mut c_void) -> () {
1002        unsafe {
1003            drop(Box::from_raw(data));
1004        }
1005    }
1006}
1007
1008value_conversions!(External);
1009
1010#[derive(Debug)]
1011pub struct ArrayBuffer(Value);
1012
1013impl ArrayBuffer {
1014    pub fn new(env: &Env, len: usize) -> Result<Self> {
1015        let mut ptr: *mut js_value_t = ptr::null_mut();
1016
1017        let status = unsafe { js_create_arraybuffer(env.ptr, len, ptr::null_mut(), &mut ptr) };
1018
1019        check_status!(env, status);
1020
1021        Ok(Self(Value { env: env.ptr, ptr }))
1022    }
1023
1024    pub fn as_slice(&self) -> &[u8] {
1025        let mut len: usize = 0;
1026        let mut data: *mut c_void = ptr::null_mut();
1027
1028        unsafe {
1029            js_get_arraybuffer_info(self.0.env, self.0.ptr, &mut data, &mut len);
1030        }
1031
1032        unsafe { slice::from_raw_parts(data as *const u8, len) }
1033    }
1034
1035    pub fn as_mut_slice(&mut self) -> &mut [u8] {
1036        let mut len: usize = 0;
1037        let mut data: *mut c_void = ptr::null_mut();
1038
1039        unsafe {
1040            js_get_arraybuffer_info(self.0.env, self.0.ptr, &mut data, &mut len);
1041        }
1042
1043        unsafe { slice::from_raw_parts_mut(data as *mut u8, len) }
1044    }
1045
1046    pub fn to_vec(&self) -> Vec<u8> {
1047        self.as_slice().to_vec()
1048    }
1049
1050    pub fn copy_from_slice(&mut self, slice: &[u8]) {
1051        self.as_mut_slice().copy_from_slice(slice)
1052    }
1053
1054    pub fn clone_from_slice(&mut self, slice: &[u8]) {
1055        self.as_mut_slice().clone_from_slice(slice)
1056    }
1057}
1058
1059value_conversions!(ArrayBuffer);
1060
1061pub trait TypedArray<T> {
1062    fn as_slice(&self) -> &[T];
1063
1064    fn as_mut_slice(&mut self) -> &mut [T];
1065
1066    fn to_vec(&self) -> Vec<T>
1067    where
1068        T: Clone,
1069    {
1070        self.as_slice().to_vec()
1071    }
1072
1073    fn copy_from_slice(&mut self, slice: &[T])
1074    where
1075        T: Copy,
1076    {
1077        self.as_mut_slice().copy_from_slice(slice)
1078    }
1079
1080    fn clone_from_slice(&mut self, slice: &[T])
1081    where
1082        T: Clone,
1083    {
1084        self.as_mut_slice().clone_from_slice(slice)
1085    }
1086}
1087
1088macro_rules! define_typedarray {
1089    ($name:ident, $type:ident, $kind:ident) => {
1090        #[derive(Debug)]
1091        pub struct $name(Value);
1092
1093        impl $name {
1094            pub fn new(env: &Env, len: usize) -> Result<Self> {
1095                let arraybuffer = ArrayBuffer::new(env, len * size_of::<$type>())?;
1096
1097                let mut ptr: *mut js_value_t = ptr::null_mut();
1098
1099                let status = unsafe {
1100                    js_create_typedarray(
1101                        env.ptr,
1102                        js_typedarray_type_t::$kind,
1103                        len,
1104                        arraybuffer.0.ptr,
1105                        0,
1106                        &mut ptr,
1107                    )
1108                };
1109
1110                check_status!(env, status);
1111
1112                Ok(Self(Value { env: env.ptr, ptr }))
1113            }
1114
1115            pub fn with_slice(env: &Env, slice: &[$type]) -> Result<Self> {
1116                let mut typedarray = $name::new(env, slice.len())?;
1117
1118                typedarray.copy_from_slice(slice);
1119
1120                Ok(typedarray)
1121            }
1122        }
1123
1124        impl TypedArray<$type> for $name {
1125            fn as_slice(&self) -> &[$type] {
1126                let mut len: usize = 0;
1127                let mut data: *mut c_void = ptr::null_mut();
1128
1129                unsafe {
1130                    js_get_typedarray_info(
1131                        self.0.env,
1132                        self.0.ptr,
1133                        ptr::null_mut(),
1134                        &mut data,
1135                        &mut len,
1136                        ptr::null_mut(),
1137                        ptr::null_mut(),
1138                    );
1139                }
1140
1141                unsafe { slice::from_raw_parts(data as *const $type, len) }
1142            }
1143
1144            fn as_mut_slice(&mut self) -> &mut [$type] {
1145                let mut len: usize = 0;
1146                let mut data: *mut c_void = ptr::null_mut();
1147
1148                unsafe {
1149                    js_get_typedarray_info(
1150                        self.0.env,
1151                        self.0.ptr,
1152                        ptr::null_mut(),
1153                        &mut data,
1154                        &mut len,
1155                        ptr::null_mut(),
1156                        ptr::null_mut(),
1157                    );
1158                }
1159
1160                unsafe { slice::from_raw_parts_mut(data as *mut $type, len) }
1161            }
1162        }
1163
1164        value_conversions!($name);
1165    };
1166}
1167
1168define_typedarray!(Int8Array, i8, js_int8array);
1169define_typedarray!(Uint8Array, u8, js_uint8array);
1170define_typedarray!(Uint8ClampedArray, u8, js_uint8clampedarray);
1171define_typedarray!(Int16Array, i16, js_int16array);
1172define_typedarray!(Uint16Array, u16, js_uint16array);
1173define_typedarray!(Int32Array, i32, js_int32array);
1174define_typedarray!(Uint32Array, u32, js_uint32array);
1175define_typedarray!(Float32Array, f32, js_float32array);
1176define_typedarray!(Float64Array, f64, js_float64array);
1177define_typedarray!(BigInt64Array, i32, js_bigint64array);
1178define_typedarray!(BigUint64Array, u32, js_biguint64array);
1179
1180macro_rules! define_error {
1181    ($name:ident, $create:ident) => {
1182        #[derive(Debug)]
1183        pub struct $name(Value);
1184
1185        impl $name {
1186            pub fn new(env: &Env, message: &str) -> Self {
1187                let message = String::new(env, message).unwrap();
1188
1189                let mut ptr: *mut js_value_t = std::ptr::null_mut();
1190
1191                unsafe {
1192                    $create(env.ptr, std::ptr::null_mut(), message.0.ptr, &mut ptr);
1193                }
1194
1195                Self(Value { env: env.ptr, ptr })
1196            }
1197        }
1198
1199        value_conversions!($name);
1200    };
1201}
1202
1203define_error!(Error, js_create_error);
1204define_error!(TypeError, js_create_type_error);
1205define_error!(RangeError, js_create_range_error);
1206define_error!(SyntaxError, js_create_syntax_error);
1207define_error!(ReferenceError, js_create_reference_error);
1208
1209#[macro_export]
1210macro_rules! bare_exports {
1211    ($name:ident, $exports:expr) => {
1212        #[unsafe(no_mangle)]
1213        pub unsafe extern "C" fn $name(
1214            env: *mut $crate::ffi::js_env_t,
1215            _: *mut $crate::ffi::js_value_t,
1216        ) -> *mut $crate::ffi::js_value_t {
1217            let result: Result<$crate::Value, $crate::Value> = $exports(crate::Env::from(env));
1218
1219            match result {
1220                Ok(result) => result.into(),
1221                Err(error) => {
1222                    unsafe {
1223                        $crate::ffi::js_throw(env, error.into());
1224                    }
1225
1226                    std::ptr::null_mut()
1227                }
1228            }
1229        }
1230    };
1231}
1232
1233#[macro_export]
1234macro_rules! bare_module {
1235    ($exports:expr) => {
1236        $crate::bare_exports!(bare_register_module_v0, $exports);
1237    };
1238}