1use crate::{qjs, Ctx, Error, Result};
2use core::{fmt, hash::Hash, mem, ops::Deref, result::Result as StdResult, str};
3
4pub mod array;
5pub mod atom;
6mod bigint;
7pub mod convert;
8pub(crate) mod exception;
9pub mod function;
10pub mod module;
11pub mod object;
12pub mod promise;
13pub mod proxy;
14mod string;
15mod symbol;
16
17pub use array::Array;
18pub use atom::Atom;
19pub use bigint::BigInt;
20pub use convert::{Coerced, FromAtom, FromIteratorJs, FromJs, IntoAtom, IntoJs, IteratorJs};
21pub use exception::Exception;
22pub use function::{Constructor, Function};
23pub use module::{Module, WriteOptions, WriteOptionsEndianness};
24pub use object::{Filter, Object};
25pub use promise::Promise;
26pub use proxy::Proxy;
27pub use string::{CString, String};
28pub use symbol::Symbol;
29
30pub mod array_buffer;
31pub mod iterable;
32pub mod typed_array;
33
34pub use array_buffer::ArrayBuffer;
35pub use iterable::{Iterable, JsIterator};
36pub use typed_array::TypedArray;
37
38pub struct Value<'js> {
40 pub(crate) ctx: Ctx<'js>,
41 pub(crate) value: qjs::JSValue,
42}
43
44impl<'js> PartialEq for Value<'js> {
45 fn eq(&self, other: &Self) -> bool {
46 let tag = unsafe { qjs::JS_VALUE_GET_TAG(self.value) };
47 let tag_other = unsafe { qjs::JS_VALUE_GET_TAG(other.value) };
48
49 let bits = unsafe { qjs::JS_VALUE_GET_FLOAT64(self.value).to_bits() };
50 let bits_other = unsafe { qjs::JS_VALUE_GET_FLOAT64(other.value).to_bits() };
51
52 tag == tag_other && bits == bits_other
53 }
54}
55
56impl<'js> Eq for Value<'js> {}
57
58impl<'js> Hash for Value<'js> {
59 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
60 let tag = unsafe { qjs::JS_VALUE_GET_TAG(self.value) };
61 let bits = unsafe { qjs::JS_VALUE_GET_FLOAT64(self.value).to_bits() };
62 state.write_i32(tag);
63 state.write_u64(bits)
64 }
65}
66
67impl<'js> Clone for Value<'js> {
68 fn clone(&self) -> Self {
69 let ctx = self.ctx.clone();
70 let value = unsafe { qjs::JS_DupValue(ctx.as_ptr(), self.value) };
71 Self { ctx, value }
72 }
73}
74
75impl<'js> Drop for Value<'js> {
76 fn drop(&mut self) {
77 unsafe {
78 qjs::JS_FreeValue(self.ctx.as_ptr(), self.value);
79 }
80 }
81}
82
83impl<'js> fmt::Debug for Value<'js> {
84 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85 let type_ = self.type_of();
86 type_.fmt(f)?;
87 use Type::*;
88 match type_ {
89 Bool | Int | Float => {
90 write!(f, "(")?;
91 match type_ {
92 Bool => unsafe { self.get_bool() }.fmt(f)?,
93 Int => unsafe { self.get_int() }.fmt(f)?,
94 Float => unsafe { self.get_float() }.fmt(f)?,
95 _ => unreachable!(),
96 }
97 write!(f, ")")?;
98 }
99 String => {
100 write!(f, "(")?;
101 unsafe { self.ref_string() }.to_string().fmt(f)?;
102 write!(f, ")")?;
103 }
104 Symbol | Object | Array | Function | Constructor | Promise | Proxy => {
105 write!(f, "(")?;
106 unsafe { self.get_ptr() }.fmt(f)?;
107 write!(f, ")")?;
108 }
109 Exception => {
110 writeln!(f, "(")?;
111 self.as_exception().unwrap().fmt(f)?;
112 writeln!(f, ")")?;
113 }
114 Null => "null".fmt(f)?,
115 Undefined => "undefined".fmt(f)?,
116 Uninitialized => "uninitialized".fmt(f)?,
117 Module => "module".fmt(f)?,
118 BigInt => "BigInt".fmt(f)?,
119 Unknown => "unknown".fmt(f)?,
120 }
121 Ok(())
122 }
123}
124
125impl<'js> Value<'js> {
126 #[inline]
128 pub(crate) unsafe fn from_js_value(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
129 Self { ctx, value }
130 }
131
132 #[inline]
133 pub(crate) unsafe fn from_js_value_const(ctx: Ctx<'js>, value: qjs::JSValueConst) -> Self {
134 let value = qjs::JS_DupValue(ctx.as_ptr(), value);
135 Self { ctx, value }
136 }
137
138 #[inline]
139 pub(crate) fn as_js_value(&self) -> qjs::JSValueConst {
140 self.value
141 }
142
143 #[inline]
144 pub(crate) fn into_js_value(self) -> qjs::JSValue {
145 let value = self.value;
146 unsafe { qjs::JS_FreeContext(self.ctx.as_ptr()) };
147 mem::forget(self);
148 value
149 }
150
151 #[inline]
152 pub fn new_uninitialized(ctx: Ctx<'js>) -> Self {
153 let value = qjs::JS_UNINITIALIZED;
154 Self { ctx, value }
155 }
156
157 #[inline]
158 pub fn new_undefined(ctx: Ctx<'js>) -> Self {
159 let value = qjs::JS_UNDEFINED;
160 Self { ctx, value }
161 }
162
163 #[inline]
164 pub fn new_null(ctx: Ctx<'js>) -> Self {
165 let value = qjs::JS_NULL;
166 Self { ctx, value }
167 }
168
169 #[inline]
171 pub fn new_bool(ctx: Ctx<'js>, value: bool) -> Self {
172 let value = if value { qjs::JS_TRUE } else { qjs::JS_FALSE };
173 Self { ctx, value }
174 }
175
176 #[inline]
178 pub fn ctx(&self) -> &Ctx<'js> {
179 &self.ctx
180 }
181
182 #[inline]
184 pub(crate) unsafe fn get_bool(&self) -> bool {
185 qjs::JS_VALUE_GET_BOOL(self.value)
186 }
187
188 pub fn as_bool(&self) -> Option<bool> {
190 if self.is_bool() {
191 Some(unsafe { self.get_bool() })
192 } else {
193 None
194 }
195 }
196
197 #[inline]
199 pub fn new_int(ctx: Ctx<'js>, value: i32) -> Self {
200 let value = qjs::JS_MKVAL(qjs::JS_TAG_INT, value);
201 Self { ctx, value }
202 }
203
204 #[inline]
205 pub(crate) unsafe fn get_int(&self) -> i32 {
206 qjs::JS_VALUE_GET_INT(self.value)
207 }
208
209 pub fn as_int(&self) -> Option<i32> {
211 if self.is_int() {
212 Some(unsafe { self.get_int() })
213 } else {
214 None
215 }
216 }
217
218 #[inline]
220 pub fn new_float(ctx: Ctx<'js>, value: f64) -> Self {
221 let value = qjs::JS_NewFloat64(value);
222 Self { ctx, value }
223 }
224
225 #[inline]
226 pub(crate) unsafe fn get_float(&self) -> f64 {
227 qjs::JS_VALUE_GET_FLOAT64(self.value)
228 }
229
230 pub fn as_float(&self) -> Option<f64> {
232 if self.is_float() {
233 Some(unsafe { self.get_float() })
234 } else {
235 None
236 }
237 }
238
239 #[inline]
241 pub fn new_big_int(ctx: Ctx<'js>, value: i64) -> Self {
242 let value = unsafe { qjs::JS_NewBigInt64(ctx.as_ptr(), value) };
243 Self { ctx, value }
244 }
245
246 #[inline]
248 pub fn new_number(ctx: Ctx<'js>, value: f64) -> Self {
249 let int = value as i32;
250 #[allow(clippy::float_cmp)]
251 let value = if value == int as f64 {
253 qjs::JS_MKVAL(qjs::JS_TAG_INT, int)
254 } else {
255 qjs::JS_NewFloat64(value)
256 };
257 Self { ctx, value }
258 }
259
260 pub fn as_number(&self) -> Option<f64> {
262 if self.is_int() {
263 Some(unsafe { self.get_int() as _ })
264 } else if self.is_float() {
265 Some(unsafe { self.get_float() })
266 } else {
267 None
268 }
269 }
270
271 #[allow(unused)]
272 #[inline]
273 pub(crate) fn new_ptr(ctx: Ctx<'js>, tag: qjs::c_int, ptr: *mut qjs::c_void) -> Self {
274 let value = qjs::JS_MKPTR(tag, ptr);
275 Self { ctx, value }
276 }
277
278 #[allow(unused)]
279 #[inline]
280 pub(crate) fn new_ptr_const(ctx: Ctx<'js>, tag: qjs::c_int, ptr: *mut qjs::c_void) -> Self {
281 let value = unsafe { qjs::JS_DupValue(ctx.as_ptr(), qjs::JS_MKPTR(tag, ptr)) };
282 Self { ctx, value }
283 }
284
285 #[inline]
286 pub(crate) unsafe fn get_ptr(&self) -> *mut qjs::c_void {
287 qjs::JS_VALUE_GET_PTR(self.value)
288 }
289
290 #[inline]
292 pub fn is_null(&self) -> bool {
293 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
294 qjs::JS_TAG_NULL == tag
295 }
296
297 #[inline]
299 pub fn is_undefined(&self) -> bool {
300 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
301 qjs::JS_TAG_UNDEFINED == tag
302 }
303
304 #[inline]
306 pub fn is_bool(&self) -> bool {
307 qjs::JS_TAG_BOOL == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
308 }
309
310 #[inline]
312 pub fn is_int(&self) -> bool {
313 qjs::JS_TAG_INT == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
314 }
315
316 #[inline]
318 pub fn is_float(&self) -> bool {
319 qjs::JS_TAG_FLOAT64 == unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) }
320 }
321
322 #[inline]
324 pub fn is_number(&self) -> bool {
325 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
326 qjs::JS_TAG_INT == tag || qjs::JS_TAG_FLOAT64 == tag
327 }
328
329 #[inline]
331 pub fn is_string(&self) -> bool {
332 qjs::JS_TAG_STRING == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
333 }
334
335 #[inline]
337 pub fn is_symbol(&self) -> bool {
338 qjs::JS_TAG_SYMBOL == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
339 }
340
341 #[inline]
343 pub fn is_object(&self) -> bool {
344 qjs::JS_TAG_OBJECT == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
345 }
346
347 #[inline]
349 pub fn is_module(&self) -> bool {
350 qjs::JS_TAG_MODULE == unsafe { qjs::JS_VALUE_GET_TAG(self.value) }
351 }
352
353 #[inline]
355 pub fn is_array(&self) -> bool {
356 unsafe { qjs::JS_IsArray(self.value) }
357 }
358
359 #[inline]
361 pub fn is_function(&self) -> bool {
362 unsafe { qjs::JS_IsFunction(self.ctx.as_ptr(), self.value) }
363 }
364
365 #[inline]
367 pub fn is_constructor(&self) -> bool {
368 unsafe { qjs::JS_IsConstructor(self.ctx.as_ptr(), self.value) }
369 }
370
371 #[inline]
373 pub fn is_promise(&self) -> bool {
374 unsafe { qjs::JS_PromiseState(self.ctx.as_ptr(), self.value) >= 0 }
375 }
376
377 #[inline]
379 pub fn is_exception(&self) -> bool {
380 unsafe { qjs::JS_IsException(self.value) }
381 }
382
383 #[inline]
385 pub fn is_error(&self) -> bool {
386 unsafe { qjs::JS_IsError(self.value) }
387 }
388
389 #[inline]
391 pub fn is_big_int(&self) -> bool {
392 unsafe { qjs::JS_IsBigInt(self.value) }
393 }
394
395 #[inline]
397 pub fn is_proxy(&self) -> bool {
398 unsafe { qjs::JS_IsProxy(self.value) }
399 }
400
401 #[inline]
403 pub fn as_value(&self) -> &Self {
404 self
405 }
406
407 #[inline]
408 pub(crate) fn into_value(self) -> Self {
409 self
410 }
411
412 pub fn get<T: FromJs<'js>>(&self) -> Result<T> {
414 T::from_js(self.ctx(), self.clone())
415 }
416
417 pub fn as_raw(&self) -> qjs::JSValue {
419 self.value
420 }
421
422 pub unsafe fn from_raw(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
430 Self::from_js_value(ctx, value)
431 }
432}
433
434impl<'js> AsRef<Value<'js>> for Value<'js> {
435 fn as_ref(&self) -> &Value<'js> {
436 self
437 }
438}
439
440macro_rules! type_impls {
441 ($($type:ident: $name:ident => $($tag:ident)|+,)*) => {
443 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
445 #[repr(u8)]
446 pub enum Type {
447 $($type,)*
448 Unknown
449 }
450
451 impl Type {
452 pub const fn is_void(self) -> bool {
454 use Type::*;
455 matches!(self, Uninitialized | Undefined | Null)
456 }
457
458 pub const fn interpretable_as(self, other: Self) -> bool {
460 use Type::*;
461
462 if (self as u8) == (other as u8){
463 return true
464 }
465 match other{
466 Float => matches!(self, Int),
467 Object => matches!(self, Array | Function | Constructor | Exception | Promise | Proxy),
468 Function => matches!(self, Constructor),
469 _ => false
470 }
471 }
472
473 pub const fn as_str(self) -> &'static str {
475 match self {
476 $(Type::$type => stringify!($name),)*
477 Type::Unknown => "Unknown type",
478 }
479 }
480 }
481
482 impl AsRef<str> for Type {
483 fn as_ref(&self) -> &str {
484 self.as_str()
485 }
486 }
487
488 impl fmt::Display for Type {
489 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
490 self.as_str().fmt(f)
491 }
492 }
493
494 impl str::FromStr for Type {
495 type Err = ();
496
497 fn from_str(s: &str) -> StdResult<Self, Self::Err> {
498 Ok(match s {
499 $(stringify!($name) => Type::$type,)*
500 _ => return Err(()),
501 })
502 }
503 }
504
505 impl<'js> Value<'js> {
506 pub fn type_of(&self) -> Type {
508 let tag = unsafe { qjs::JS_VALUE_GET_NORM_TAG(self.value) };
509 match tag {
510 $($(qjs::$tag)|+ if type_impls!(@cond $type self) => Type::$type,)*
511 _ => Type::Unknown,
512 }
513 }
514
515 pub fn type_name(&self) -> &'static str {
517 self.type_of().as_str()
518 }
519 }
520 };
521
522 (@cond Array $self:expr) => { $self.is_array() };
523 (@cond Constructor $self:expr) => { $self.is_constructor() };
524 (@cond Function $self:expr) => { $self.is_function() };
525 (@cond Promise $self:expr) => { $self.is_promise() };
526 (@cond Exception $self:expr) => { $self.is_error() };
527 (@cond Proxy $self:expr) => { $self.is_proxy() };
528 (@cond $type:ident $self:expr) => { true };
529}
530
531type_impls! {
532 Uninitialized: uninitialized => JS_TAG_UNINITIALIZED,
533 Undefined: undefined => JS_TAG_UNDEFINED,
534 Null: null => JS_TAG_NULL,
535 Bool: bool => JS_TAG_BOOL,
536 Int: int => JS_TAG_INT,
537 Float: float => JS_TAG_FLOAT64,
538 String: string => JS_TAG_STRING,
539 Symbol: symbol => JS_TAG_SYMBOL,
540 Array: array => JS_TAG_OBJECT,
541 Constructor: constructor => JS_TAG_OBJECT,
542 Function: function => JS_TAG_OBJECT,
543 Promise: promise => JS_TAG_OBJECT,
544 Exception: exception => JS_TAG_OBJECT,
545 Proxy: proxy => JS_TAG_OBJECT,
546 Object: object => JS_TAG_OBJECT,
547 Module: module => JS_TAG_MODULE,
548 BigInt: big_int => JS_TAG_BIG_INT | JS_TAG_SHORT_BIG_INT,
549}
550
551macro_rules! sub_types {
552 ($( $head:ident$(->$sub_type:ident)* $as:ident $ref:ident $into:ident $try_into:ident $from:ident,)*) => {
553 $(
554 impl<'js> $head<'js> {
555 #[inline]
557 pub fn as_value(&self) -> &Value<'js> {
558 &self.0.as_value()
559 }
560
561 #[inline]
563 pub fn into_value(self) -> Value<'js> {
564 self.0.into_value()
565 }
566
567 pub fn into_inner(self) -> sub_types!(@head_ty $($sub_type),*) {
569 self.0
570 }
571 pub fn as_inner(&self) -> & sub_types!(@head_ty $($sub_type),*) {
573 &self.0
574 }
575
576 pub fn ctx(&self) -> &Ctx<'js>{
578 self.0.ctx()
579 }
580
581 pub fn from_value(value: Value<'js>) -> Result<Self> {
583 let type_ = value.type_of();
584 if type_.interpretable_as(Type::$head) {
585 Ok(sub_types!(@wrap $head$(->$sub_type)* value))
586 } else {
587 Err(Error::new_from_js(type_.as_str(), Type::$head.as_str()))
588 }
589 }
590
591 #[allow(unused)]
592 pub(crate) unsafe fn from_js_value_const(ctx: Ctx<'js>, value: qjs::JSValueConst) -> Self {
593 let v = Value::from_js_value_const(ctx, value);
594 debug_assert!(v.$as().is_some(),"tried to cource js value {:?} to the wrong type `{}`, this is a rquickjs bug",v, stringify!($head));
595 sub_types!(@wrap $head$(->$sub_type)* v)
596 }
597
598 #[allow(unused)]
599 pub(crate) unsafe fn from_js_value(ctx: Ctx<'js>, value: qjs::JSValue) -> Self {
600 let v = Value::from_js_value(ctx, value);
601 debug_assert!(v.$as().is_some(),"tried to cource js value {:?} to the wrong type `{}`, this is a rquickjs bug",v, stringify!($head));
602 sub_types!(@wrap $head$(->$sub_type)* v)
603 }
604
605 #[allow(unused)]
606 pub(crate) fn into_js_value(self) -> qjs::JSValue{
607 self.0.into_js_value()
608 }
609
610 #[allow(unused)]
611 pub(crate) fn as_js_value(&self) -> qjs::JSValueConst{
612 self.0.as_js_value()
613 }
614 }
615
616 impl<'js> Deref for $head<'js> {
617 type Target = sub_types!(@head_ty $($sub_type),*);
618
619 fn deref(&self) -> &Self::Target {
620 &self.0
621 }
622 }
623
624 sub_types!(@imp_as_ref $head$(,$sub_type)*);
625
626 impl<'js> Value<'js> {
627 #[doc = concat!("Interpret as [`",stringify!($head),"`]")]
628 #[inline]
632 pub unsafe fn $ref(&self) -> &$head<'js> {
633 &*(self as *const _ as *const $head)
634 }
635
636 #[doc = concat!("Try reinterpret as [`",stringify!($head),"`]")]
637 pub fn $as(&self) -> Option<&$head<'js>> {
638 if self.type_of().interpretable_as(Type::$head) {
639 Some(unsafe { self.$ref() })
640 } else {
641 None
642 }
643 }
644
645 #[doc = concat!("Try convert into [`",stringify!($head),"`]")]
646 pub fn $into(self) -> Option<$head<'js>> {
647 if self.type_of().interpretable_as(Type::$head) {
648 Some(sub_types!(@wrap $head$(->$sub_type)* self))
649 } else {
650 None
651 }
652 }
653
654 #[doc = concat!("Try convert into [`",stringify!($head),"`] returning self if the conversion fails.")]
655 pub fn $try_into(self) -> core::result::Result<$head<'js>, Value<'js>> {
656 if self.type_of().interpretable_as(Type::$head) {
657 Ok(sub_types!(@wrap $head$(->$sub_type)* self))
658 } else {
659 Err(self)
660 }
661 }
662
663 #[doc = concat!("Convert from [`",stringify!($head),"`]")]
664 pub fn $from(value: $head<'js>) -> Self {
665 value.into_value()
666 }
667 }
668
669 impl<'js> From<$head<'js>> for Value<'js> {
670 fn from(value: $head<'js>) -> Self {
671 value.into_value()
672 }
673 }
674
675 impl<'js> FromJs<'js> for $head<'js> {
676 fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
677 Self::from_value(value)
678 }
679 }
680
681 impl<'js> IntoJs<'js> for $head<'js> {
682 fn into_js(self, _ctx: &Ctx<'js>) -> Result<Value<'js>> {
683 Ok(self.into_value())
684 }
685 }
686
687 impl<'js> IntoAtom<'js> for $head<'js>{
688 fn into_atom(self, ctx: &Ctx<'js>) -> Result<Atom<'js>> {
689 Atom::from_value(ctx.clone(), &self.into_value())
690 }
691 }
692 )*
693 };
694
695 (@type $type:ident) => { $type<'js> };
696
697 (@head $head:ident $(rem:ident)*) => { $head };
698 (@head_ty $head:ident$(,$rem:ident)*) => { $head<'js> };
699
700 (@wrap $type:ident$(->$rem:ident)+ $val:expr) => { $type(sub_types!(@wrap $($rem)->* $val)) };
701 (@wrap Value $val:expr) => { $val };
702
703 (@imp_as_ref $type:ident,Value) => {
711 impl<'js> AsRef<Value<'js>> for $type<'js> {
712 fn as_ref(&self) -> &Value<'js> {
713 &self.0
714 }
715 }
716 };
717 (@imp_as_ref $type:ident,$inner:ident$(,$rem:ident)*) => {
718 impl<'js> AsRef<$inner<'js>> for $type<'js> {
719 fn as_ref(&self) -> &$inner<'js> {
720 &self.0
721 }
722 }
723
724 impl<'js> AsRef<Value<'js>> for $type<'js> {
725 fn as_ref(&self) -> &Value<'js> {
726 self.0.as_ref()
727 }
728 }
729 };
730}
731
732sub_types! {
733 String->Value as_string ref_string into_string try_into_string from_string,
734 Symbol->Value as_symbol ref_symbol into_symbol try_into_symbol from_symbol,
735 Object->Value as_object ref_object into_object try_into_object from_object,
736 Function->Object->Value as_function ref_function into_function try_into_function from_function,
737 Constructor->Function->Object->Value as_constructor ref_constructor into_constructor try_into_constructor from_constructor,
738 Promise->Object->Value as_promise ref_promise into_promise try_into_promise from_promise,
739 Array->Object->Value as_array ref_array into_array try_into_array from_array,
740 Exception->Object->Value as_exception ref_exception into_exception try_into_exception from_exception,
741 BigInt->Value as_big_int ref_big_int into_big_int try_into_big_int from_big_int,
742 Proxy->Object->Value as_proxy ref_proxy into_proxy try_into_proxy from_proxy,
743}
744
745macro_rules! void_types {
746 ($($(#[$meta:meta])* $type:ident $new:ident;)*) => {
747 $(
748 $(#[$meta])*
749 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
750 #[allow(dead_code)]
751 pub struct $type;
752
753 #[allow(dead_code)]
754 impl $type {
755 pub fn into_value<'js>(self, ctx: Ctx<'js>) -> Value<'js> {
757 Value::$new(ctx)
758 }
759
760 pub fn from_value<'js>(value: Value<'js>) -> Result<Self> {
762 if value.type_of() == Type::$type {
763 Ok(Self)
764 } else {
765 Err(Error::new_from_js("value", Type::$type.as_str()))
766 }
767 }
768 }
769
770 impl<'js> FromJs<'js> for $type {
771 fn from_js(_: &Ctx<'js>, value: Value<'js>) -> Result<Self> {
772 Self::from_value(value)
773 }
774 }
775
776 impl<'js> IntoJs<'js> for $type {
777 fn into_js(self, ctx: &Ctx<'js>) -> Result<Value<'js>> {
778 Ok(self.into_value(ctx.clone()))
779 }
780 }
781 )*
782 };
783}
784
785void_types! {
786 Uninitialized new_uninitialized;
788
789 Undefined new_undefined;
791
792 Null new_null;
794}
795
796#[cfg(test)]
797mod test {
798 use crate::*;
799
800 #[test]
801 fn type_matches() {
802 assert!(Type::Bool.interpretable_as(Type::Bool));
803
804 assert!(Type::Object.interpretable_as(Type::Object));
805 assert!(Type::Array.interpretable_as(Type::Object));
806 assert!(Type::Function.interpretable_as(Type::Object));
807
808 assert!(!Type::Object.interpretable_as(Type::Array));
809 assert!(!Type::Object.interpretable_as(Type::Function));
810
811 assert!(!Type::Bool.interpretable_as(Type::Int));
812 }
813
814 #[test]
815 fn big_int() {
816 test_with(|ctx| {
817 let val: Value = ctx.eval(r#"1n"#).unwrap();
818 assert_eq!(val.type_of(), Type::BigInt);
819 let val: Value = ctx.eval(r#"999999999999999999999n"#).unwrap();
820 assert_eq!(val.type_of(), Type::BigInt);
821 let val = Value::new_big_int(ctx.clone(), 1245);
822 assert_eq!(val.type_of(), Type::BigInt);
823 let val = Value::new_big_int(ctx, 9999999999999999);
824 assert_eq!(val.type_of(), Type::BigInt);
825 });
826 }
827}