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