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}