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