bare_rust/
lib.rs

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::apply),
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    pub fn call<'a, C, R, A>(&self, receiver: C, args: A) -> Result<R>
913    where
914        C: Into<Value>,
915        A: IntoIterator<Item = &'a Value>,
916        R: From<Value>,
917    {
918        let env = Env::from(self.0.env);
919
920        let mut args: Vec<_> = args.into_iter().map(|value| value.ptr).collect();
921
922        let mut ptr: *mut js_value_t = ptr::null_mut();
923
924        let status = unsafe {
925            js_call_function(
926                env.ptr,
927                receiver.into().ptr,
928                self.0.ptr,
929                args.len(),
930                args.as_mut_ptr(),
931                &mut ptr,
932            )
933        };
934
935        check_status!(env, status);
936
937        Ok(Value { env: env.ptr, ptr }.into())
938    }
939
940    extern "C" fn apply(env: *mut js_env_t, info: *mut js_callback_info_t) -> *mut js_value_t {
941        let mut len: usize = 0;
942        let mut receiver: *mut js_value_t = ptr::null_mut();
943        let mut data: *mut c_void = ptr::null_mut();
944
945        unsafe {
946            js_get_callback_info(
947                env,
948                info,
949                &mut len,
950                ptr::null_mut(),
951                &mut receiver,
952                &mut data,
953            );
954        }
955
956        let mut args = Vec::new();
957
958        if len > 0 {
959            args.resize(len, ptr::null_mut());
960
961            unsafe {
962                js_get_callback_info(
963                    env,
964                    info,
965                    &mut len,
966                    args.as_mut_ptr(),
967                    ptr::null_mut(),
968                    ptr::null_mut(),
969                );
970            }
971        }
972
973        let closure =
974            unsafe { &mut *(data as *mut Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t>) };
975
976        closure(
977            &Env::from(env),
978            &Callback {
979                env,
980                args,
981                receiver,
982            },
983        )
984    }
985
986    extern "C" fn drop(_: *mut js_env_t, data: *mut c_void, _: *mut c_void) -> () {
987        unsafe {
988            drop(Box::from_raw(data));
989        }
990    }
991}
992
993value_conversions!(Function);
994
995#[derive(Debug)]
996pub struct External(Value);
997
998impl External {
999    pub fn new<T: 'static>(env: &Env, value: T) -> Result<Self> {
1000        let data = Box::into_raw(Box::new(value)) as *mut _;
1001
1002        let mut ptr: *mut js_value_t = ptr::null_mut();
1003
1004        let status = unsafe {
1005            js_create_external(
1006                env.ptr,
1007                data,
1008                Some(External::drop),
1009                ptr::null_mut(),
1010                &mut ptr,
1011            )
1012        };
1013
1014        check_status!(env, status);
1015
1016        Ok(Self(Value { env: env.ptr, ptr }))
1017    }
1018
1019    extern "C" fn drop(_: *mut js_env_t, data: *mut c_void, _: *mut c_void) -> () {
1020        unsafe {
1021            drop(Box::from_raw(data));
1022        }
1023    }
1024}
1025
1026value_conversions!(External);
1027
1028impl<T> AsRef<T> for External {
1029    fn as_ref(&self) -> &T {
1030        let mut ptr: *mut c_void = ptr::null_mut();
1031
1032        unsafe {
1033            js_get_value_external(self.0.env, self.0.ptr, &mut ptr);
1034        }
1035
1036        unsafe { &*(ptr as *const T) }
1037    }
1038}
1039
1040impl<T> AsMut<T> for External {
1041    fn as_mut(&mut self) -> &mut T {
1042        let mut ptr: *mut c_void = ptr::null_mut();
1043
1044        unsafe {
1045            js_get_value_external(self.0.env, self.0.ptr, &mut ptr);
1046        }
1047
1048        unsafe { &mut *(ptr as *mut T) }
1049    }
1050}
1051
1052#[derive(Debug)]
1053pub struct ArrayBuffer(Value);
1054
1055impl ArrayBuffer {
1056    pub fn new(env: &Env, len: usize) -> Result<Self> {
1057        let mut ptr: *mut js_value_t = ptr::null_mut();
1058
1059        let status = unsafe { js_create_arraybuffer(env.ptr, len, ptr::null_mut(), &mut ptr) };
1060
1061        check_status!(env, status);
1062
1063        Ok(Self(Value { env: env.ptr, ptr }))
1064    }
1065
1066    pub fn as_slice(&self) -> &[u8] {
1067        let mut len: usize = 0;
1068        let mut data: *mut c_void = ptr::null_mut();
1069
1070        unsafe {
1071            js_get_arraybuffer_info(self.0.env, self.0.ptr, &mut data, &mut len);
1072        }
1073
1074        unsafe { slice::from_raw_parts(data as *const u8, len) }
1075    }
1076
1077    pub fn as_mut_slice(&mut self) -> &mut [u8] {
1078        let mut len: usize = 0;
1079        let mut data: *mut c_void = ptr::null_mut();
1080
1081        unsafe {
1082            js_get_arraybuffer_info(self.0.env, self.0.ptr, &mut data, &mut len);
1083        }
1084
1085        unsafe { slice::from_raw_parts_mut(data as *mut u8, len) }
1086    }
1087
1088    pub fn to_vec(&self) -> Vec<u8> {
1089        self.as_slice().to_vec()
1090    }
1091
1092    pub fn copy_from_slice(&mut self, slice: &[u8]) {
1093        self.as_mut_slice().copy_from_slice(slice)
1094    }
1095
1096    pub fn clone_from_slice(&mut self, slice: &[u8]) {
1097        self.as_mut_slice().clone_from_slice(slice)
1098    }
1099}
1100
1101value_conversions!(ArrayBuffer);
1102
1103pub trait TypedArray<T> {
1104    fn as_slice(&self) -> &[T];
1105
1106    fn as_mut_slice(&mut self) -> &mut [T];
1107
1108    fn to_vec(&self) -> Vec<T>
1109    where
1110        T: Clone,
1111    {
1112        self.as_slice().to_vec()
1113    }
1114
1115    fn copy_from_slice(&mut self, slice: &[T])
1116    where
1117        T: Copy,
1118    {
1119        self.as_mut_slice().copy_from_slice(slice)
1120    }
1121
1122    fn clone_from_slice(&mut self, slice: &[T])
1123    where
1124        T: Clone,
1125    {
1126        self.as_mut_slice().clone_from_slice(slice)
1127    }
1128}
1129
1130macro_rules! define_typedarray {
1131    ($name:ident, $type:ident, $kind:ident) => {
1132        #[derive(Debug)]
1133        pub struct $name(Value);
1134
1135        impl $name {
1136            pub fn new(env: &Env, len: usize) -> Result<Self> {
1137                let arraybuffer = ArrayBuffer::new(env, len * size_of::<$type>())?;
1138
1139                let mut ptr: *mut js_value_t = ptr::null_mut();
1140
1141                let status = unsafe {
1142                    js_create_typedarray(
1143                        env.ptr,
1144                        js_typedarray_type_t::$kind,
1145                        len,
1146                        arraybuffer.0.ptr,
1147                        0,
1148                        &mut ptr,
1149                    )
1150                };
1151
1152                check_status!(env, status);
1153
1154                Ok(Self(Value { env: env.ptr, ptr }))
1155            }
1156
1157            pub fn with_slice(env: &Env, slice: &[$type]) -> Result<Self> {
1158                let mut typedarray = $name::new(env, slice.len())?;
1159
1160                typedarray.copy_from_slice(slice);
1161
1162                Ok(typedarray)
1163            }
1164        }
1165
1166        impl TypedArray<$type> for $name {
1167            fn as_slice(&self) -> &[$type] {
1168                let mut len: usize = 0;
1169                let mut data: *mut c_void = ptr::null_mut();
1170
1171                unsafe {
1172                    js_get_typedarray_info(
1173                        self.0.env,
1174                        self.0.ptr,
1175                        ptr::null_mut(),
1176                        &mut data,
1177                        &mut len,
1178                        ptr::null_mut(),
1179                        ptr::null_mut(),
1180                    );
1181                }
1182
1183                unsafe { slice::from_raw_parts(data as *const $type, len) }
1184            }
1185
1186            fn as_mut_slice(&mut self) -> &mut [$type] {
1187                let mut len: usize = 0;
1188                let mut data: *mut c_void = ptr::null_mut();
1189
1190                unsafe {
1191                    js_get_typedarray_info(
1192                        self.0.env,
1193                        self.0.ptr,
1194                        ptr::null_mut(),
1195                        &mut data,
1196                        &mut len,
1197                        ptr::null_mut(),
1198                        ptr::null_mut(),
1199                    );
1200                }
1201
1202                unsafe { slice::from_raw_parts_mut(data as *mut $type, len) }
1203            }
1204        }
1205
1206        value_conversions!($name);
1207    };
1208}
1209
1210define_typedarray!(Int8Array, i8, js_int8array);
1211define_typedarray!(Uint8Array, u8, js_uint8array);
1212define_typedarray!(Uint8ClampedArray, u8, js_uint8clampedarray);
1213define_typedarray!(Int16Array, i16, js_int16array);
1214define_typedarray!(Uint16Array, u16, js_uint16array);
1215define_typedarray!(Int32Array, i32, js_int32array);
1216define_typedarray!(Uint32Array, u32, js_uint32array);
1217define_typedarray!(Float32Array, f32, js_float32array);
1218define_typedarray!(Float64Array, f64, js_float64array);
1219define_typedarray!(BigInt64Array, i32, js_bigint64array);
1220define_typedarray!(BigUint64Array, u32, js_biguint64array);
1221
1222macro_rules! define_error {
1223    ($name:ident, $create:ident) => {
1224        #[derive(Debug)]
1225        pub struct $name(Value);
1226
1227        impl $name {
1228            pub fn new(env: &Env, message: &str) -> Self {
1229                let message = String::new(env, message).unwrap();
1230
1231                let mut ptr: *mut js_value_t = std::ptr::null_mut();
1232
1233                unsafe {
1234                    $create(env.ptr, std::ptr::null_mut(), message.0.ptr, &mut ptr);
1235                }
1236
1237                Self(Value { env: env.ptr, ptr })
1238            }
1239        }
1240
1241        value_conversions!($name);
1242    };
1243}
1244
1245define_error!(Error, js_create_error);
1246define_error!(TypeError, js_create_type_error);
1247define_error!(RangeError, js_create_range_error);
1248define_error!(SyntaxError, js_create_syntax_error);
1249define_error!(ReferenceError, js_create_reference_error);
1250
1251#[macro_export]
1252macro_rules! bare_exports {
1253    ($name:ident, $exports:expr) => {
1254        #[unsafe(no_mangle)]
1255        pub unsafe extern "C" fn $name(
1256            env: *mut $crate::ffi::js_env_t,
1257            _: *mut $crate::ffi::js_value_t,
1258        ) -> *mut $crate::ffi::js_value_t {
1259            let result: Result<$crate::Value, $crate::Value> = $exports(crate::Env::from(env));
1260
1261            match result {
1262                Ok(result) => result.into(),
1263                Err(error) => {
1264                    unsafe {
1265                        $crate::ffi::js_throw(env, error.into());
1266                    }
1267
1268                    std::ptr::null_mut()
1269                }
1270            }
1271        }
1272    };
1273}
1274
1275#[macro_export]
1276macro_rules! bare_module {
1277    ($exports:expr) => {
1278        $crate::bare_exports!(bare_register_module_v0, $exports);
1279    };
1280}