bare_rust/
lib.rs

1use std::ffi::{c_void, CString};
2use std::ptr;
3use std::slice;
4use std::string;
5
6pub use bare_rust_ffi as ffi;
7
8use ffi::*;
9
10macro_rules! js_check_status {
11    ($env:expr, $status:expr) => {
12        if $status == JS_PENDING_EXCEPTION {
13            return Err($env.pending_exception().unwrap());
14        } else if $status != 0 {
15            panic!("Uncaught JavaScript exception");
16        }
17    };
18}
19
20pub type Result<T> = std::result::Result<T, Value>;
21
22#[derive(Debug)]
23pub struct Env {
24    ptr: *mut js_env_t,
25}
26
27impl Env {
28    pub fn pending_exception(&self) -> Option<Value> {
29        let mut ptr: *mut js_value_t = ptr::null_mut();
30
31        unsafe {
32            js_get_and_clear_last_exception(self.ptr, &mut ptr);
33        }
34
35        if ptr.is_null() {
36            None
37        } else {
38            Some(Value { env: self.ptr, ptr })
39        }
40    }
41}
42
43impl From<*mut js_env_t> for Env {
44    fn from(ptr: *mut js_env_t) -> Self {
45        return Self { ptr };
46    }
47}
48
49#[derive(Debug)]
50pub struct Value {
51    env: *mut js_env_t,
52    ptr: *mut js_value_t,
53}
54
55impl From<Value> for *mut js_value_t {
56    fn from(value: Value) -> Self {
57        value.ptr
58    }
59}
60
61#[derive(Debug)]
62pub struct Undefined(pub Value);
63
64impl Undefined {
65    pub fn new(env: &Env) -> Self {
66        let mut ptr: *mut js_value_t = ptr::null_mut();
67
68        unsafe {
69            js_get_undefined(env.ptr, &mut ptr);
70        }
71
72        Self(Value { env: env.ptr, ptr })
73    }
74}
75
76impl From<Undefined> for *mut js_value_t {
77    fn from(undefined: Undefined) -> Self {
78        undefined.0.ptr
79    }
80}
81
82impl From<Value> for Undefined {
83    fn from(value: Value) -> Self {
84        Self(value)
85    }
86}
87
88#[derive(Debug)]
89pub struct Null(pub Value);
90
91impl Null {
92    pub fn new(env: &Env) -> Self {
93        let mut ptr: *mut js_value_t = ptr::null_mut();
94
95        unsafe {
96            js_get_null(env.ptr, &mut ptr);
97        }
98
99        Self(Value { env: env.ptr, ptr })
100    }
101}
102
103impl From<Null> for *mut js_value_t {
104    fn from(null: Null) -> Self {
105        null.0.ptr
106    }
107}
108
109impl From<Value> for Null {
110    fn from(value: Value) -> Self {
111        Self(value)
112    }
113}
114
115#[derive(Debug)]
116pub struct Boolean(pub Value);
117
118impl Boolean {
119    pub fn new(env: &Env, value: bool) -> Self {
120        let mut ptr: *mut js_value_t = ptr::null_mut();
121
122        unsafe {
123            js_get_boolean(env.ptr, value, &mut ptr);
124        }
125
126        Self(Value { env: env.ptr, ptr })
127    }
128}
129
130impl From<Boolean> for bool {
131    fn from(boolean: Boolean) -> Self {
132        let mut value = false;
133
134        unsafe {
135            js_get_value_bool(boolean.0.env, boolean.0.ptr, &mut value);
136        }
137
138        value
139    }
140}
141
142impl From<Boolean> for *mut js_value_t {
143    fn from(boolean: Boolean) -> Self {
144        boolean.0.ptr
145    }
146}
147
148impl From<Value> for Boolean {
149    fn from(value: Value) -> Self {
150        Self(value)
151    }
152}
153
154#[derive(Debug)]
155pub struct Number(pub Value);
156
157impl Number {
158    pub fn with_i32(env: &Env, value: i32) -> Self {
159        let mut ptr: *mut js_value_t = ptr::null_mut();
160
161        unsafe {
162            js_create_int32(env.ptr, value, &mut ptr);
163        }
164
165        Self(Value { env: env.ptr, ptr })
166    }
167
168    pub fn with_u32(env: &Env, value: u32) -> Self {
169        let mut ptr: *mut js_value_t = ptr::null_mut();
170
171        unsafe {
172            js_create_uint32(env.ptr, value, &mut ptr);
173        }
174
175        Self(Value { env: env.ptr, ptr })
176    }
177
178    pub fn with_i64(env: &Env, value: i64) -> Self {
179        let mut ptr: *mut js_value_t = ptr::null_mut();
180
181        unsafe {
182            js_create_int64(env.ptr, value, &mut ptr);
183        }
184
185        Self(Value { env: env.ptr, ptr })
186    }
187
188    pub fn with_f64(env: &Env, value: f64) -> Self {
189        let mut ptr: *mut js_value_t = ptr::null_mut();
190
191        unsafe {
192            js_create_double(env.ptr, value, &mut ptr);
193        }
194
195        Self(Value { env: env.ptr, ptr })
196    }
197}
198
199impl From<Number> for i32 {
200    fn from(number: Number) -> Self {
201        let mut value = 0;
202
203        unsafe {
204            js_get_value_int32(number.0.env, number.0.ptr, &mut value);
205        }
206
207        value
208    }
209}
210
211impl From<Number> for u32 {
212    fn from(number: Number) -> Self {
213        let mut value = 0;
214
215        unsafe {
216            js_get_value_uint32(number.0.env, number.0.ptr, &mut value);
217        }
218
219        value
220    }
221}
222
223impl From<Number> for i64 {
224    fn from(number: Number) -> Self {
225        let mut value = 0;
226
227        unsafe {
228            js_get_value_int64(number.0.env, number.0.ptr, &mut value);
229        }
230
231        value
232    }
233}
234
235impl From<Number> for f64 {
236    fn from(number: Number) -> Self {
237        let mut value = 0.0;
238
239        unsafe {
240            js_get_value_double(number.0.env, number.0.ptr, &mut value);
241        }
242
243        value
244    }
245}
246
247impl From<Number> for *mut js_value_t {
248    fn from(number: Number) -> Self {
249        number.0.ptr
250    }
251}
252
253impl From<Value> for Number {
254    fn from(value: Value) -> Self {
255        Self(value)
256    }
257}
258
259#[derive(Debug)]
260pub struct BigInt(pub Value);
261
262impl BigInt {
263    pub fn with_i64(env: &Env, value: i64) -> Self {
264        let mut ptr: *mut js_value_t = ptr::null_mut();
265
266        unsafe {
267            js_create_bigint_int64(env.ptr, value, &mut ptr);
268        }
269
270        Self(Value { env: env.ptr, ptr })
271    }
272
273    pub fn with_u64(env: &Env, value: u64) -> Self {
274        let mut ptr: *mut js_value_t = ptr::null_mut();
275
276        unsafe {
277            js_create_bigint_uint64(env.ptr, value, &mut ptr);
278        }
279
280        Self(Value { env: env.ptr, ptr })
281    }
282}
283
284impl From<BigInt> for i64 {
285    fn from(bigint: BigInt) -> Self {
286        let mut value = 0;
287
288        unsafe {
289            js_get_value_bigint_int64(bigint.0.env, bigint.0.ptr, &mut value, ptr::null_mut());
290        }
291
292        value
293    }
294}
295
296impl From<BigInt> for u64 {
297    fn from(bigint: BigInt) -> Self {
298        let mut value = 0;
299
300        unsafe {
301            js_get_value_bigint_uint64(bigint.0.env, bigint.0.ptr, &mut value, ptr::null_mut());
302        }
303
304        value
305    }
306}
307
308impl From<BigInt> for *mut js_value_t {
309    fn from(bigint: BigInt) -> Self {
310        bigint.0.ptr
311    }
312}
313
314impl From<Value> for BigInt {
315    fn from(value: Value) -> Self {
316        Self(value)
317    }
318}
319
320#[derive(Debug)]
321pub struct String(pub Value);
322
323impl String {
324    pub fn new(env: &Env, value: &str) -> Result<Self> {
325        let mut ptr: *mut js_value_t = ptr::null_mut();
326
327        let status = unsafe {
328            js_create_string_utf8(
329                env.ptr,
330                value.as_ptr().cast(),
331                value.len() as usize,
332                &mut ptr,
333            )
334        };
335
336        js_check_status!(env, status);
337
338        Ok(Self(Value { env: env.ptr, ptr }))
339    }
340
341    pub fn to_bytes(&self) -> Vec<u8> {
342        let mut len = 0;
343
344        unsafe {
345            js_get_value_string_utf8(self.0.env, self.0.ptr, ptr::null_mut(), 0, &mut len);
346        }
347
348        let mut result = Vec::new();
349
350        result.resize(len, 0);
351
352        unsafe {
353            js_get_value_string_utf8(self.0.env, self.0.ptr, result.as_mut_ptr(), len, &mut len);
354        }
355
356        result
357    }
358}
359
360impl From<String> for string::String {
361    fn from(string: String) -> Self {
362        return string::String::from_utf8(string.to_bytes()).unwrap();
363    }
364}
365
366impl From<String> for *mut js_value_t {
367    fn from(string: String) -> Self {
368        string.0.ptr
369    }
370}
371
372impl From<Value> for String {
373    fn from(value: Value) -> Self {
374        Self(value)
375    }
376}
377
378#[derive(Debug)]
379pub struct Object(pub Value);
380
381impl Object {
382    pub fn new(env: &Env) -> Result<Self> {
383        let mut ptr: *mut js_value_t = ptr::null_mut();
384
385        let status = unsafe { js_create_object(env.ptr, &mut ptr) };
386
387        js_check_status!(env, status);
388
389        Ok(Self(Value { env: env.ptr, ptr }))
390    }
391
392    pub fn get_named_property<T>(&self, name: &str) -> Result<T>
393    where
394        T: From<Value>,
395    {
396        let env = Env::from(self.0.env);
397
398        let key = CString::new(name).unwrap();
399
400        let mut ptr: *mut js_value_t = ptr::null_mut();
401
402        let status =
403            unsafe { js_get_named_property(self.0.env, self.0.ptr, key.as_ptr(), &mut ptr) };
404
405        js_check_status!(env, status);
406
407        Ok(T::from(Value { env: env.ptr, ptr }))
408    }
409
410    pub fn has_named_property<T>(&self, name: &str) -> Result<bool> {
411        let env = Env::from(self.0.env);
412
413        let key = CString::new(name).unwrap();
414
415        let mut result = false;
416
417        let status =
418            unsafe { js_has_named_property(self.0.env, self.0.ptr, key.as_ptr(), &mut result) };
419
420        js_check_status!(env, status);
421
422        Ok(result)
423    }
424
425    pub fn set_named_property<T>(&mut self, name: &str, value: T) -> Result<()>
426    where
427        T: Into<*mut js_value_t>,
428    {
429        let env = Env::from(self.0.env);
430
431        let key = CString::new(name).unwrap();
432
433        let status =
434            unsafe { js_set_named_property(self.0.env, self.0.ptr, key.as_ptr(), T::into(value)) };
435
436        js_check_status!(env, status);
437
438        Ok(())
439    }
440}
441
442impl From<Object> for *mut js_value_t {
443    fn from(object: Object) -> Self {
444        object.0.ptr
445    }
446}
447
448impl From<Value> for Object {
449    fn from(value: Value) -> Self {
450        Self(value)
451    }
452}
453
454#[derive(Debug)]
455pub struct Callback {
456    env: *mut js_env_t,
457    args: Vec<*mut js_value_t>,
458    receiver: *mut js_value_t,
459}
460
461impl Callback {
462    pub fn arg<T>(&self, i: usize) -> Option<T>
463    where
464        T: From<Value>,
465    {
466        if i < self.args.len() {
467            Some(T::from(Value {
468                env: self.env,
469                ptr: self.args[i],
470            }))
471        } else {
472            None
473        }
474    }
475
476    pub fn receiver<T>(&self) -> T
477    where
478        T: From<Value>,
479    {
480        T::from(Value {
481            env: self.env,
482            ptr: self.receiver,
483        })
484    }
485}
486
487#[derive(Debug)]
488pub struct Function(Value);
489
490impl Function {
491    pub fn new<F, R>(env: &Env, function: F) -> Result<Self>
492    where
493        F: FnMut(&Env, &Callback) -> Result<R>,
494        R: Into<*mut js_value_t>,
495    {
496        let mut function = function;
497
498        let closure: Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t> =
499            Box::new(move |env, info| match function(env, info) {
500                Ok(result) => result.into(),
501                Err(error) => {
502                    unsafe {
503                        js_throw(env.ptr, error.ptr);
504                    }
505
506                    ptr::null_mut()
507                }
508            });
509
510        let data = Box::into_raw(Box::new(closure)) as *mut _;
511
512        let mut ptr: *mut js_value_t = ptr::null_mut();
513
514        let status = unsafe {
515            js_create_function(
516                env.ptr,
517                ptr::null_mut(),
518                0,
519                Some(Function::call),
520                data,
521                &mut ptr,
522            )
523        };
524
525        js_check_status!(env, status);
526
527        unsafe {
528            js_add_finalizer(
529                env.ptr,
530                ptr,
531                data,
532                Some(Function::drop),
533                ptr::null_mut(),
534                ptr::null_mut(),
535            );
536        }
537
538        Ok(Self(Value { env: env.ptr, ptr }))
539    }
540
541    extern "C" fn call(env: *mut js_env_t, info: *mut js_callback_info_t) -> *mut js_value_t {
542        let mut len: usize = 0;
543        let mut receiver: *mut js_value_t = ptr::null_mut();
544        let mut data: *mut c_void = ptr::null_mut();
545
546        unsafe {
547            js_get_callback_info(
548                env,
549                info,
550                &mut len,
551                ptr::null_mut(),
552                &mut receiver,
553                &mut data,
554            );
555        }
556
557        let mut args = Vec::new();
558
559        args.resize(len, ptr::null_mut());
560
561        if len > 0 {
562            unsafe {
563                js_get_callback_info(
564                    env,
565                    info,
566                    &mut len,
567                    args.as_mut_ptr(),
568                    ptr::null_mut(),
569                    ptr::null_mut(),
570                );
571            }
572        }
573
574        let closure: &mut Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t> =
575            unsafe { &mut *(data as *mut Box<dyn FnMut(&Env, &Callback) -> *mut js_value_t>) };
576
577        return closure(
578            &Env::from(env),
579            &Callback {
580                env,
581                args,
582                receiver,
583            },
584        );
585    }
586
587    extern "C" fn drop(_: *mut js_env_t, data: *mut c_void, _: *mut c_void) -> () {
588        let _: Box<Box<dyn FnMut(&Env, &Callback)>> = unsafe { Box::from_raw(data as *mut _) };
589    }
590}
591
592impl From<Function> for *mut js_value_t {
593    fn from(function: Function) -> Self {
594        function.0.ptr
595    }
596}
597
598impl From<Value> for Function {
599    fn from(value: Value) -> Self {
600        Self(value)
601    }
602}
603
604#[derive(Debug)]
605pub struct ArrayBuffer(Value);
606
607impl ArrayBuffer {
608    pub fn new(env: &Env, len: usize) -> Result<Self> {
609        let mut ptr: *mut js_value_t = ptr::null_mut();
610
611        let status = unsafe { js_create_arraybuffer(env.ptr, len, ptr::null_mut(), &mut ptr) };
612
613        js_check_status!(env, status);
614
615        Ok(Self(Value { env: env.ptr, ptr }))
616    }
617
618    pub fn as_slice(&self) -> &[u8] {
619        self.as_mut_slice()
620    }
621
622    pub fn as_mut_slice(&self) -> &mut [u8] {
623        let mut len: usize = 0;
624        let mut data: *mut c_void = ptr::null_mut();
625
626        unsafe {
627            js_get_arraybuffer_info(self.0.env, self.0.ptr, &mut data, &mut len);
628        }
629
630        unsafe { slice::from_raw_parts_mut(data as *mut u8, len) }
631    }
632}
633
634impl From<ArrayBuffer> for *mut js_value_t {
635    fn from(arraybuffer: ArrayBuffer) -> Self {
636        arraybuffer.0.ptr
637    }
638}
639
640impl From<Value> for ArrayBuffer {
641    fn from(value: Value) -> Self {
642        Self(value)
643    }
644}
645
646pub trait TypedArray<T> {
647    fn as_slice(&self) -> &[T];
648    fn as_mut_slice(&self) -> &mut [T];
649}
650
651#[derive(Debug)]
652pub struct Uint8Array(Value);
653
654impl Uint8Array {
655    pub fn new(env: &Env, len: usize) -> Result<Self> {
656        let arraybuffer = ArrayBuffer::new(env, len)?;
657
658        let mut ptr: *mut js_value_t = ptr::null_mut();
659
660        let status = unsafe {
661            js_create_typedarray(
662                env.ptr,
663                js_typedarray_type_t::js_uint8array,
664                len,
665                arraybuffer.0.ptr,
666                0,
667                &mut ptr,
668            )
669        };
670
671        js_check_status!(env, status);
672
673        Ok(Self(Value { env: env.ptr, ptr }))
674    }
675}
676
677impl TypedArray<u8> for Uint8Array {
678    fn as_slice(&self) -> &[u8] {
679        self.as_mut_slice()
680    }
681
682    fn as_mut_slice(&self) -> &mut [u8] {
683        let mut len: usize = 0;
684        let mut data: *mut c_void = ptr::null_mut();
685
686        unsafe {
687            js_get_typedarray_info(
688                self.0.env,
689                self.0.ptr,
690                ptr::null_mut(),
691                &mut data,
692                &mut len,
693                ptr::null_mut(),
694                ptr::null_mut(),
695            );
696        }
697
698        unsafe { slice::from_raw_parts_mut(data as *mut u8, len) }
699    }
700}
701
702impl From<Uint8Array> for *mut js_value_t {
703    fn from(uint8array: Uint8Array) -> Self {
704        uint8array.0.ptr
705    }
706}
707
708impl From<Value> for Uint8Array {
709    fn from(value: Value) -> Self {
710        Self(value)
711    }
712}