1 use std::collections::{BTreeMap, HashMap};
2 use std::hash::Hash;
3 use std::fmt;
4 use std::error;
5 use std::mem;
6 use std::borrow::Cow;
7 use webcore::void::Void;
8 use webcore::try_from::{TryFrom, TryInto};
9 use webcore::number::{self, Number};
10 use webcore::object::Object;
11 use webcore::array::Array;
12 use webcore::serialization::JsSerialize;
13 use webcore::reference_type::ReferenceType;
14 use webcore::instance_of::InstanceOf;
15 use webcore::symbol::Symbol;
16 use webcore::type_name::type_name_opt;
17 use webapi::error::TypeError;
18 
19 /// A unit type representing JavaScript's `undefined`.
20 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
21 pub struct Undefined;
22 
23 /// A unit type representing JavaScript's `null`.
24 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
25 pub struct Null;
26 
27 /// A type representing a reference to a JavaScript value.
28 #[repr(C)]
29 #[derive(Debug)]
30 pub struct Reference( i32 );
31 
32 impl Reference {
33     #[doc(hidden)]
34     #[inline]
from_raw_unchecked( refid: i32 ) -> Reference35     pub unsafe fn from_raw_unchecked( refid: i32 ) -> Reference {
36         __js_raw_asm!( "Module.STDWEB_PRIVATE.increment_refcount( $0 );", refid );
37         Reference( refid )
38     }
39 
40     #[doc(hidden)]
41     #[inline]
from_raw_unchecked_noref( refid: i32 ) -> Reference42     pub(crate) unsafe fn from_raw_unchecked_noref( refid: i32 ) -> Reference {
43         Reference( refid )
44     }
45 
46     #[doc(hidden)]
47     #[inline]
as_raw( &self ) -> i3248     pub fn as_raw( &self ) -> i32 {
49         self.0
50     }
51 
52     /// Converts this reference into the given type `T`; checks whenever the reference
53     /// is really of type `T` and returns `None` if it's not.
54     #[inline]
downcast< T: ReferenceType >( self ) -> Option< T >55     pub fn downcast< T: ReferenceType >( self ) -> Option< T > {
56         if T::instance_of( &self ) {
57             Some( unsafe { T::from_reference_unchecked( self ) } )
58         } else {
59             None
60         }
61     }
62 }
63 
64 impl PartialEq for Reference {
65     #[inline]
eq( &self, other: &Reference ) -> bool66     fn eq( &self, other: &Reference ) -> bool {
67         let result = self.0 == other.0;
68 
69         debug_assert_eq!( {
70             let real_result: bool = js!( return @{self} === @{other}; ).try_into().unwrap();
71             real_result
72         }, result );
73 
74         result
75     }
76 }
77 
78 impl Eq for Reference {}
79 
80 impl Clone for Reference {
81     #[inline]
clone( &self ) -> Self82     fn clone( &self ) -> Self {
83         unsafe {
84             Reference::from_raw_unchecked( self.as_raw() )
85         }
86     }
87 }
88 
89 impl Drop for Reference {
90     #[inline]
drop( &mut self )91     fn drop( &mut self ) {
92         __js_raw_asm!( "Module.STDWEB_PRIVATE.decrement_refcount( $0 );", self.0 );
93     }
94 }
95 
96 impl AsRef< Reference > for Reference {
97     #[inline]
as_ref( &self ) -> &Self98     fn as_ref( &self ) -> &Self {
99         self
100     }
101 }
102 
103 macro_rules! __impl_infallible_try_from {
104     (($($impl_arg:tt)*) ($($src_arg:tt)*) ($($dst_arg:tt)*) ($($bounds:tt)*)) => {
105         impl< $($impl_arg)* > TryFrom< $($src_arg)* > for $($dst_arg)* where $($bounds)* {
106             type Error = $crate::unstable::Void;
107 
108             #[inline]
109             fn try_from( source: $($src_arg)* ) -> Result< Self, Self::Error > {
110                 Ok( source.into() )
111             }
112         }
113     };
114 }
115 
116 macro_rules! impl_infallible_try_from {
117     (impl< $($impl_arg:tt),* > for $src:ty => $dst:ty where ($($bounds:tt)*); $($rest:tt)*) => {
118         __impl_infallible_try_from!( ($($impl_arg),*) ($src) ($dst) ($($bounds)*) );
119         impl_infallible_try_from!( $($rest)* );
120     };
121 
122     (impl< $($impl_arg:tt),* > for $src:ty => $dst:ty; $($rest:tt)*) => {
123         __impl_infallible_try_from!( ($($impl_arg),*) ($src) ($dst) () );
124         impl_infallible_try_from!( $($rest)* );
125     };
126 
127     ($src:ty => $dst:ty; $($rest:tt)*) => {
128         __impl_infallible_try_from!( () ($src) ($dst) () );
129         impl_infallible_try_from!( $($rest)* );
130 
131     };
132 
133     () => {};
134 }
135 
136 impl_infallible_try_from! {
137     Reference => Reference;
138     impl< 'a > for &'a Reference => &'a Reference;
139 }
140 
141 /// A type representing a JavaScript value.
142 ///
143 /// This type implements a rich set of conversions
144 /// from and into standard Rust types, for example:
145 ///
146 /// ```rust
147 /// let v1: Value = "Hello world!".into();
148 /// let v2: Value = true.into();
149 /// let v3: Value = vec![ 1, 2, 3 ].into();
150 /// let v4: Value = Null.into();
151 /// let v5: Value = 123_u64.try_into().unwrap();
152 ///
153 /// let v1_r: String = v1.try_into().unwrap();
154 /// let v2_r: bool = v2.try_into().unwrap();
155 /// let v3_r: Vec< i32 > = v3.try_into().unwrap();
156 /// let v4_r: Option< String > = v4.try_into().unwrap(); // Will be `None`.
157 /// let v5_r: u64 = v5.try_into().unwrap();
158 /// ```
159 #[allow(missing_docs)]
160 #[derive(Clone, PartialEq, Debug)]
161 pub enum Value {
162     Undefined,
163     Null,
164     Bool( bool ),
165     Number( Number ),
166     Symbol( Symbol ),
167     String( String ),
168     Reference( Reference )
169 }
170 
171 impl Value {
172     /// Checks whenever the Value is of the Null variant.
173     #[inline]
is_null( &self ) -> bool174     pub fn is_null( &self ) -> bool {
175         if let Value::Null = *self {
176             true
177         } else {
178             false
179         }
180     }
181 
182     /// Checks whenever the Value is of the Symbol variant.
183     #[inline]
is_symbol( &self ) -> bool184     pub fn is_symbol( &self ) -> bool {
185         if let Value::Symbol( _ ) = *self {
186             true
187         } else {
188             false
189         }
190     }
191 
192     /// Checks whenever the Value is of the Reference variant.
193     #[inline]
is_reference( &self ) -> bool194     pub fn is_reference( &self ) -> bool {
195         if let Value::Reference( _ ) = *self {
196             true
197         } else {
198             false
199         }
200     }
201 
202     /// Checks whenever the Value is a reference to an `Object`.
203     #[inline]
is_object( &self ) -> bool204     pub fn is_object( &self ) -> bool {
205         if let Value::Reference( ref reference ) = *self {
206             Object::instance_of( reference )
207         } else {
208             false
209         }
210     }
211 
212     /// Checks whenever the Value is a reference to an `Array`.
213     #[inline]
is_array( &self ) -> bool214     pub fn is_array( &self ) -> bool {
215         if let Value::Reference( ref reference ) = *self {
216             Array::instance_of( reference )
217         } else {
218             false
219         }
220     }
221 
222     /// Gets a reference to the [Reference](struct.Reference.html) inside this `Value`.
223     #[inline]
as_reference( &self ) -> Option< &Reference >224     pub fn as_reference( &self ) -> Option< &Reference > {
225         match *self {
226             Value::Reference( ref reference ) => Some( reference ),
227             _ => None
228         }
229     }
230 
231     /// Gets a reference to the [Object](struct.Object.html) inside this `Value`.
232     #[inline]
as_object( &self ) -> Option< &Object >233     pub fn as_object( &self ) -> Option< &Object > {
234         match *self {
235             Value::Reference( ref reference ) if Object::instance_of( reference ) => {
236                 unsafe {
237                     Some( mem::transmute( reference ) )
238                 }
239             },
240             _ => None
241         }
242     }
243 
244     /// Gets a reference to the [Array](struct.Array.html) inside this `Value`.
245     #[inline]
as_array( &self ) -> Option< &Array >246     pub fn as_array( &self ) -> Option< &Array > {
247         match *self {
248             Value::Reference( ref reference ) if Array::instance_of( reference ) => {
249                 unsafe {
250                     Some( mem::transmute( reference ) )
251                 }
252             },
253             _ => None
254         }
255     }
256 
257     /// Returns the [Reference](struct.Reference.html) inside this `Value`.
258     #[inline]
into_reference( self ) -> Option< Reference >259     pub fn into_reference( self ) -> Option< Reference > {
260         match self {
261             Value::Reference( reference ) => Some( reference ),
262             _ => None
263         }
264     }
265 
266     /// Returns the [Object](struct.Object.html) inside this `Value`.
267     #[inline]
into_object( self ) -> Option< Object >268     pub fn into_object( self ) -> Option< Object > {
269         match self {
270             Value::Reference( reference ) => reference.try_into().ok(),
271             _ => None
272         }
273     }
274 
275     /// Returns the [Array](struct.Array.html) inside this `Value`.
276     #[inline]
into_array( self ) -> Option< Array >277     pub fn into_array( self ) -> Option< Array > {
278         match self {
279             Value::Reference( reference ) => reference.try_into().ok(),
280             _ => None
281         }
282     }
283 
284     /// Converts a [Reference](struct.Reference.html) inside this `Value` into
285     /// the given type `T`; doesn't check whenever the reference is really of type `T`.
286     ///
287     /// In cases where the value is not a `Reference` a `None` is returned.
288     #[inline]
into_reference_unchecked< T: ReferenceType >( self ) -> Option< T >289     pub unsafe fn into_reference_unchecked< T: ReferenceType >( self ) -> Option< T > {
290         let reference: Option< Reference > = self.try_into().ok();
291         reference.map( |reference| T::from_reference_unchecked( reference ) )
292     }
293 
294     /// Returns the `String` inside this `Value`.
295     #[inline]
into_string( self ) -> Option< String >296     pub fn into_string( self ) -> Option< String > {
297         match self {
298             Value::String( string ) => Some( string ),
299             _ => None
300         }
301     }
302 
303     /// Returns a borrow of the string inside this `Value`.
304     #[inline]
as_str( &self ) -> Option< &str >305     pub fn as_str( &self ) -> Option< &str > {
306         match *self {
307             Value::String( ref string ) => Some( string.as_str() ),
308             _ => None
309         }
310     }
311 }
312 
313 impl AsRef< Value > for Value {
314     #[inline]
as_ref( &self ) -> &Self315     fn as_ref( &self ) -> &Self {
316         self
317     }
318 }
319 
320 impl From< Undefined > for Value {
321     #[inline]
from( _: Undefined ) -> Self322     fn from( _: Undefined ) -> Self {
323         Value::Undefined
324     }
325 }
326 
327 impl< 'a > From< &'a Undefined > for Value {
328     #[inline]
from( _: &'a Undefined ) -> Self329     fn from( _: &'a Undefined ) -> Self {
330         Value::Undefined
331     }
332 }
333 
334 impl< 'a > From< &'a mut Undefined > for Value {
335     #[inline]
from( _: &'a mut Undefined ) -> Self336     fn from( _: &'a mut Undefined ) -> Self {
337         Value::Undefined
338     }
339 }
340 
341 impl From< Null > for Value {
342     #[inline]
from( _: Null ) -> Self343     fn from( _: Null ) -> Self {
344         Value::Null
345     }
346 }
347 
348 impl< 'a > From< &'a Null > for Value {
349     #[inline]
from( _: &'a Null ) -> Self350     fn from( _: &'a Null ) -> Self {
351         Value::Null
352     }
353 }
354 
355 impl< 'a > From< &'a mut Null > for Value {
356     #[inline]
from( _: &'a mut Null ) -> Self357     fn from( _: &'a mut Null ) -> Self {
358         Value::Null
359     }
360 }
361 
362 impl From< bool > for Value {
363     #[inline]
from( value: bool ) -> Self364     fn from( value: bool ) -> Self {
365         Value::Bool( value )
366     }
367 }
368 
369 impl< 'a > From< &'a bool > for Value {
370     #[inline]
from( value: &'a bool ) -> Self371     fn from( value: &'a bool ) -> Self {
372         Value::Bool( *value )
373     }
374 }
375 
376 impl< 'a > From< &'a mut bool > for Value {
377     #[inline]
from( value: &'a mut bool ) -> Self378     fn from( value: &'a mut bool ) -> Self {
379         (value as &bool).into()
380     }
381 }
382 
383 impl< 'a > From< &'a str > for Value {
384     #[inline]
from( value: &'a str ) -> Self385     fn from( value: &'a str ) -> Self {
386         Value::String( value.to_string() )
387     }
388 }
389 
390 impl< 'a > From< &'a mut str > for Value {
391     #[inline]
from( value: &'a mut str ) -> Self392     fn from( value: &'a mut str ) -> Self {
393         (value as &str).into()
394     }
395 }
396 
397 impl From< String > for Value {
398     #[inline]
from( value: String ) -> Self399     fn from( value: String ) -> Self {
400         Value::String( value )
401     }
402 }
403 
404 impl< 'a > From< &'a String > for Value {
405     #[inline]
from( value: &'a String ) -> Self406     fn from( value: &'a String ) -> Self {
407         Value::String( value.clone() )
408     }
409 }
410 
411 impl< 'a > From< &'a mut String > for Value {
412     #[inline]
from( value: &'a mut String ) -> Self413     fn from( value: &'a mut String ) -> Self {
414         (value as &String).into()
415     }
416 }
417 
418 impl From< char > for Value {
419     #[inline]
from( value: char ) -> Self420     fn from( value: char ) -> Self {
421         let mut buffer: [u8; 4] = [0; 4];
422         let string = value.encode_utf8( &mut buffer );
423         string.to_owned().into()
424     }
425 }
426 
427 impl< 'a > From< &'a char > for Value {
428     #[inline]
from( value: &'a char ) -> Self429     fn from( value: &'a char ) -> Self {
430         (*value).into()
431     }
432 }
433 
434 impl< 'a > From< &'a mut char > for Value {
435     #[inline]
from( value: &'a mut char ) -> Self436     fn from( value: &'a mut char ) -> Self {
437         (*value).into()
438     }
439 }
440 
441 impl< T > From< Vec< T > > for Value where T: JsSerialize {
442     #[inline]
from( value: Vec< T > ) -> Self443     fn from( value: Vec< T > ) -> Self {
444         value[..].into()
445     }
446 }
447 
448 impl< 'a, T > From< &'a Vec< T > > for Value where T: JsSerialize {
449     #[inline]
from( value: &'a Vec< T > ) -> Self450     fn from( value: &'a Vec< T > ) -> Self {
451         value[..].into()
452     }
453 }
454 
455 impl< 'a, T > From< &'a mut Vec< T > > for Value where T: JsSerialize {
456     #[inline]
from( value: &'a mut Vec< T > ) -> Self457     fn from( value: &'a mut Vec< T > ) -> Self {
458         value[..].into()
459     }
460 }
461 
462 impl< 'a, T > From< &'a [T] > for Value where T: JsSerialize {
463     #[inline]
from( value: &'a [T] ) -> Self464     fn from( value: &'a [T] ) -> Self {
465         let array: Array = value.into();
466         Value::Reference( array.into() )
467     }
468 }
469 
470 impl< 'a, T > From< &'a mut [T] > for Value where T: JsSerialize {
471     #[inline]
from( value: &'a mut [T] ) -> Self472     fn from( value: &'a mut [T] ) -> Self {
473         (value as &[T]).into()
474     }
475 }
476 
477 impl< K, V > From< BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
478     #[inline]
from( value: BTreeMap< K, V > ) -> Self479     fn from( value: BTreeMap< K, V > ) -> Self {
480         let object: Object = value.into();
481         Value::Reference( object.into() )
482     }
483 }
484 
485 impl< 'a, K, V > From< &'a BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
486     #[inline]
from( value: &'a BTreeMap< K, V > ) -> Self487     fn from( value: &'a BTreeMap< K, V > ) -> Self {
488         let object: Object = value.into();
489         Value::Reference( object.into() )
490     }
491 }
492 
493 impl< 'a, K, V > From< &'a mut BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
494     #[inline]
from( value: &'a mut BTreeMap< K, V > ) -> Self495     fn from( value: &'a mut BTreeMap< K, V > ) -> Self {
496         let object: Object = value.into();
497         Value::Reference( object.into() )
498     }
499 }
500 
501 impl< K, V > From< HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
502     #[inline]
from( value: HashMap< K, V > ) -> Self503     fn from( value: HashMap< K, V > ) -> Self {
504         let object: Object = value.into();
505         Value::Reference( object.into() )
506     }
507 }
508 
509 impl< 'a, K, V > From< &'a HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
510     #[inline]
from( value: &'a HashMap< K, V > ) -> Self511     fn from( value: &'a HashMap< K, V > ) -> Self {
512         let object: Object = value.into();
513         Value::Reference( object.into() )
514     }
515 }
516 
517 impl< 'a, K, V > From< &'a mut HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
518     #[inline]
from( value: &'a mut HashMap< K, V > ) -> Self519     fn from( value: &'a mut HashMap< K, V > ) -> Self {
520         let object: Object = value.into();
521         Value::Reference( object.into() )
522     }
523 }
524 
525 impl From< Reference > for Value {
526     #[inline]
from( value: Reference ) -> Self527     fn from( value: Reference ) -> Self {
528         Value::Reference( value )
529     }
530 }
531 
532 impl< 'a > From< &'a Reference > for Value {
533     #[inline]
from( value: &'a Reference ) -> Self534     fn from( value: &'a Reference ) -> Self {
535         Value::Reference( value.clone() )
536     }
537 }
538 
539 impl< 'a > From< &'a mut Reference > for Value {
540     #[inline]
from( value: &'a mut Reference ) -> Self541     fn from( value: &'a mut Reference ) -> Self {
542         (value as &Reference).into()
543     }
544 }
545 
546 macro_rules! impl_from_number {
547     ($($kind:ty)+) => {
548         $(
549             impl From< $kind > for Value {
550                 #[inline]
551                 fn from( value: $kind ) -> Self {
552                     Value::Number( value.into() )
553                 }
554             }
555 
556             impl< 'a > From< &'a $kind > for Value {
557                 #[inline]
558                 fn from( value: &'a $kind ) -> Self {
559                     Value::Number( (*value).into() )
560                 }
561             }
562 
563             impl< 'a > From< &'a mut $kind > for Value {
564                 #[inline]
565                 fn from( value: &'a mut $kind ) -> Self {
566                     (value as &$kind).into()
567                 }
568             }
569 
570             impl_infallible_try_from!( $kind => Value; );
571         )+
572     };
573 }
574 
575 impl_from_number!( i8 i16 i32 u8 u16 u32 f32 f64 );
576 impl_infallible_try_from! {
577     Value => Value;
578     Undefined => Value;
579     impl< 'a > for &'a Undefined => Value;
580     impl< 'a > for &'a mut Undefined => Value;
581     Null => Value;
582     impl< 'a > for &'a Null => Value;
583     impl< 'a > for &'a mut Null => Value;
584     bool => Value;
585     impl< 'a > for &'a bool => Value;
586     impl< 'a > for &'a mut bool => Value;
587     impl< 'a > for &'a str => Value;
588     impl< 'a > for &'a mut str => Value;
589     String => Value;
590     impl< 'a > for &'a String => Value;
591     impl< 'a > for &'a mut String => Value;
592     char => Value;
593     impl< 'a > for &'a char => Value;
594     impl< 'a > for &'a mut char => Value;
595     impl< T > for Vec< T > => Value where (T: JsSerialize);
596     impl< 'a, T > for &'a Vec< T > => Value where (T: JsSerialize);
597     impl< 'a, T > for &'a mut Vec< T > => Value where (T: JsSerialize);
598     impl< 'a, T > for &'a [T] => Value where (T: JsSerialize);
599     impl< 'a, T > for &'a mut [T] => Value where (T: JsSerialize);
600 
601     impl< K, V > for BTreeMap< K, V > => Value where (K: AsRef< str >, V: JsSerialize);
602     impl< 'a, K, V > for &'a BTreeMap< K, V > => Value where (K: AsRef< str >, V: JsSerialize);
603     impl< 'a, K, V > for &'a mut BTreeMap< K, V > => Value where (K: AsRef< str >, V: JsSerialize);
604     impl< K, V > for HashMap< K, V > => Value where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
605     impl< 'a, K, V > for &'a HashMap< K, V > => Value where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
606     impl< 'a, K, V > for &'a mut HashMap< K, V > => Value where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
607 
608     Symbol => Value;
609     Reference => Value;
610 
611     // TODO: Move these to object.rs
612     impl< K, V > for BTreeMap< K, V > => Object where (K: AsRef< str >, V: JsSerialize);
613     impl< 'a, K, V > for &'a BTreeMap< K, V > => Object where (K: AsRef< str >, V: JsSerialize);
614     impl< 'a, K, V > for &'a mut BTreeMap< K, V > => Object where (K: AsRef< str >, V: JsSerialize);
615     impl< K, V > for HashMap< K, V > => Object where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
616     impl< 'a, K, V > for &'a HashMap< K, V > => Object where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
617     impl< 'a, K, V > for &'a mut HashMap< K, V > => Object where (K: AsRef< str > + Eq + Hash, V: JsSerialize);
618 
619     // TODO: Move these to array.rs
620     impl< T > for Vec< T > => Array where (T: JsSerialize);
621     impl< 'a, T > for &'a Vec< T > => Array where (T: JsSerialize);
622     impl< 'a, T > for &'a mut Vec< T > => Array where (T: JsSerialize);
623     impl< 'a, T > for &'a [T] => Array where (T: JsSerialize);
624     impl< 'a, T > for &'a mut [T] => Array where (T: JsSerialize);
625 }
626 
627 macro_rules! impl_try_from_number {
628     ($($kind:ty)+) => {
629         $(
630             impl TryFrom< $kind > for Value {
631                 type Error = <Number as TryFrom< $kind >>::Error;
632 
633                 #[inline]
634                 fn try_from( value: $kind ) -> Result< Self, Self::Error > {
635                     Ok( Value::Number( value.try_into()? ) )
636                 }
637             }
638         )+
639     };
640 }
641 
642 impl_try_from_number!( i64 u64 usize );
643 
644 impl PartialEq< Undefined > for Value {
645     #[inline]
eq( &self, _: &Undefined ) -> bool646     fn eq( &self, _: &Undefined ) -> bool {
647         match *self {
648             Value::Undefined => true,
649             _ => false
650         }
651     }
652 }
653 
654 impl PartialEq< Null > for Value {
655     #[inline]
eq( &self, _: &Null ) -> bool656     fn eq( &self, _: &Null ) -> bool {
657         match *self {
658             Value::Null => true,
659             _ => false
660         }
661     }
662 }
663 
664 impl PartialEq< bool > for Value {
665     #[inline]
eq( &self, right: &bool ) -> bool666     fn eq( &self, right: &bool ) -> bool {
667         match *self {
668             Value::Bool( left ) => left == *right,
669             _ => false
670         }
671     }
672 }
673 
674 impl PartialEq< str > for Value {
675     #[inline]
eq( &self, right: &str ) -> bool676     fn eq( &self, right: &str ) -> bool {
677         match *self {
678             Value::String( ref left ) => left == right,
679             _ => false
680         }
681     }
682 }
683 
684 impl PartialEq< String > for Value {
685     #[inline]
eq( &self, right: &String ) -> bool686     fn eq( &self, right: &String ) -> bool {
687         match *self {
688             Value::String( ref left ) => left == right,
689             _ => false
690         }
691     }
692 }
693 
694 impl PartialEq< Number > for Value {
695     #[inline]
eq( &self, right: &Number ) -> bool696     fn eq( &self, right: &Number ) -> bool {
697         match *self {
698             Value::Number( left ) => left == *right,
699             _ => false
700         }
701     }
702 }
703 
704 impl PartialEq< Symbol > for Value {
705     #[inline]
eq( &self, right: &Symbol ) -> bool706     fn eq( &self, right: &Symbol ) -> bool {
707         match *self {
708             Value::Symbol( ref left ) => *left == *right,
709             _ => false
710         }
711     }
712 }
713 
714 impl< T: AsRef< Reference > > PartialEq< T > for Value {
715     #[inline]
eq( &self, right: &T ) -> bool716     fn eq( &self, right: &T ) -> bool {
717         match *self {
718             Value::Reference( ref left ) => left == right.as_ref(),
719             _ => false
720         }
721     }
722 }
723 
724 impl< 'a > PartialEq< Reference > for &'a Value {
725     #[inline]
eq( &self, right: &Reference ) -> bool726     fn eq( &self, right: &Reference ) -> bool {
727         (*self).eq( right )
728     }
729 }
730 
731 impl PartialEq< Value > for Reference {
732     #[inline]
eq( &self, right: &Value ) -> bool733     fn eq( &self, right: &Value ) -> bool {
734         right.eq( self )
735     }
736 }
737 
738 impl< 'a > PartialEq< &'a Value > for Reference {
739     #[inline]
eq( &self, right: &&'a Value ) -> bool740     fn eq( &self, right: &&'a Value ) -> bool {
741         let right: &'a Value = right;
742         right.eq( self )
743     }
744 }
745 
746 impl< 'a > PartialEq< Value > for &'a Reference {
747     #[inline]
eq( &self, right: &Value ) -> bool748     fn eq( &self, right: &Value ) -> bool {
749         (*self).eq( right )
750     }
751 }
752 
753 macro_rules! impl_partial_eq_boilerplate {
754     ( $( $kind:ty ),+ ) => {
755         $(
756             impl< 'a > PartialEq< &'a $kind > for Value {
757                 #[inline]
758                 fn eq( &self, right: &&'a $kind ) -> bool {
759                     let right: &'a $kind = right;
760                     self.eq( right )
761                 }
762             }
763 
764             impl< 'a > PartialEq< $kind > for &'a Value {
765                 #[inline]
766                 fn eq( &self, right: &$kind ) -> bool {
767                     (*self).eq( right )
768                 }
769             }
770 
771             impl PartialEq< Value > for $kind {
772                 #[inline]
773                 fn eq( &self, right: &Value ) -> bool {
774                     right == self
775                 }
776             }
777 
778             impl< 'a > PartialEq< &'a Value > for $kind {
779                 #[inline]
780                 fn eq( &self, right: &&'a Value ) -> bool {
781                     let right: &'a Value = right;
782                     right == self
783                 }
784             }
785 
786             impl< 'a > PartialEq< Value > for &'a $kind {
787                 #[inline]
788                 fn eq( &self, right: &Value ) -> bool {
789                     (*self).eq( right )
790                 }
791             }
792         )+
793     }
794 }
795 
796 macro_rules! impl_partial_eq_to_number {
797     ($($kind:ty)+) => {
798         $(
799             impl PartialEq< $kind > for Value {
800                 #[inline]
801                 fn eq( &self, right: &$kind ) -> bool {
802                     match *self {
803                         Value::Number( left ) => left == *right,
804                         _ => false
805                     }
806                 }
807             }
808 
809             impl_partial_eq_boilerplate!( $kind );
810         )+
811     };
812 }
813 
814 impl_partial_eq_to_number!( i8 i16 i32 i64 u8 u16 u32 u64 usize f32 f64 );
815 
816 impl_partial_eq_boilerplate! {
817     Undefined,
818     Null,
819     bool,
820     str,
821     String,
822     Number,
823     Symbol
824 }
825 
826 /// A structure denoting a conversion error encountered when
827 /// converting to or from a `Value`.
828 #[doc(hidden)]
829 #[derive(Clone, PartialEq, Eq, Debug)]
830 pub enum ConversionError {
831     TypeMismatch {
832         expected: Cow< 'static, str >,
833         actual: Cow< 'static, str >
834     },
835     NumericConversionError( number::ConversionError ),
836     ValueConversionError( Box< ConversionError > ),
837     Custom( String )
838 }
839 
extract_type_name( value: &Value ) -> Cow< 'static, str >840 fn extract_type_name( value: &Value ) -> Cow< 'static, str > {
841     match *value {
842         Value::Undefined => "undefined".into(),
843         Value::Null => "null".into(),
844         Value::Bool( _ ) => "bool".into(),
845         Value::Number( _ ) => "Number".into(),
846         Value::Symbol( _ ) => "Symbol".into(),
847         Value::String( _ ) => "String".into(),
848         Value::Reference( _ ) => "Reference".into()
849     }
850 }
851 
852 impl fmt::Display for ConversionError {
fmt( &self, formatter: &mut fmt::Formatter ) -> Result< (), fmt::Error >853     fn fmt( &self, formatter: &mut fmt::Formatter ) -> Result< (), fmt::Error > {
854         match *self {
855             ConversionError::TypeMismatch { ref expected, ref actual } => {
856                 write!( formatter, "type mismatch; expected {}, got {}", expected, actual )
857             },
858             ConversionError::NumericConversionError( ref inner ) => write!( formatter, "{}", inner ),
859             ConversionError::ValueConversionError( ref inner ) => write!( formatter, "value conversion error: {}", inner ),
860             ConversionError::Custom( ref message ) => write!( formatter, "{}", message )
861         }
862     }
863 }
864 
865 impl error::Error for ConversionError {
description( &self ) -> &str866     fn description( &self ) -> &str {
867         match *self {
868             ConversionError::TypeMismatch { .. } => "type mismatch",
869             ConversionError::NumericConversionError( ref inner ) => inner.description(),
870             ConversionError::ValueConversionError( _ ) => "value conversion error",
871             ConversionError::Custom( ref message ) => message
872         }
873     }
874 }
875 
876 impl From< number::ConversionError > for ConversionError {
from( inner: number::ConversionError ) -> Self877     fn from( inner: number::ConversionError ) -> Self {
878         ConversionError::NumericConversionError( inner )
879     }
880 }
881 
882 impl From< Void > for ConversionError {
from( _: Void ) -> Self883     fn from( _: Void ) -> Self {
884         unreachable!();
885     }
886 }
887 
888 impl From< ConversionError > for TypeError {
from( error: ConversionError ) -> TypeError889     fn from( error: ConversionError ) -> TypeError {
890         (&error).into()
891     }
892 }
893 
894 impl< 'a > From< &'a ConversionError > for TypeError {
from( error: &'a ConversionError ) -> TypeError895     fn from( error: &'a ConversionError ) -> TypeError {
896         js!( return new TypeError( @{format!( "{}", error )} ); ).try_into().unwrap()
897     }
898 }
899 
900 impl ConversionError {
901     #[inline]
type_mismatch( actual_value: &Value, expected: Cow< 'static, str > ) -> Self902     pub(crate) fn type_mismatch( actual_value: &Value, expected: Cow< 'static, str > ) -> Self {
903         ConversionError::TypeMismatch {
904             actual: extract_type_name( actual_value ),
905             expected
906         }
907     }
908 
909     #[inline]
value_conversion_error( inner: ConversionError ) -> Self910     pub(crate) fn value_conversion_error( inner: ConversionError ) -> Self {
911         ConversionError::ValueConversionError( Box::new( inner ) )
912     }
913 }
914 
915 impl TryFrom< Value > for Undefined {
916     type Error = ConversionError;
917 
918     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >919     fn try_from( value: Value ) -> Result< Self, Self::Error > {
920         match value {
921             Value::Undefined => Ok( Undefined ),
922             _ => Err( ConversionError::type_mismatch( &value, "undefined".into() ) )
923         }
924     }
925 }
926 
927 impl TryFrom< Value > for Null {
928     type Error = ConversionError;
929 
930     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >931     fn try_from( value: Value ) -> Result< Self, Self::Error > {
932         match value {
933             Value::Null => Ok( Null ),
934             _ => Err( ConversionError::type_mismatch( &value, "null".into() ) )
935         }
936     }
937 }
938 
939 impl TryFrom< Value > for () {
940     type Error = ConversionError;
941 
942     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >943     fn try_from( value: Value ) -> Result< Self, Self::Error > {
944         match value {
945             Value::Null | Value::Undefined => Ok( () ),
946             _ => Err( ConversionError::type_mismatch( &value, "null or undefined".into() ) )
947         }
948     }
949 }
950 
951 impl TryFrom< Value > for bool {
952     type Error = ConversionError;
953 
954     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >955     fn try_from( value: Value ) -> Result< Self, Self::Error > {
956         match value {
957             Value::Bool( value ) => Ok( value ),
958             _ => Err( ConversionError::type_mismatch( &value, "bool".into() ) )
959         }
960     }
961 }
962 
963 macro_rules! impl_try_into_number {
964     ($($kind:ty)+) => {
965         $(
966             impl TryFrom< Value > for $kind {
967                 type Error = ConversionError;
968 
969                 #[inline]
970                 fn try_from( value: Value ) -> Result< Self, Self::Error > {
971                     match value {
972                         Value::Number( value ) => {
973                             let result: Result< Self, _ > = value.try_into();
974                             result.map_err( |error| error.into() )
975                         },
976                         _ => {
977                             let expected = concat!( "Number which fits into ", stringify!( $kind ) );
978                             Err( ConversionError::type_mismatch( &value, expected.into() ) )
979                         }
980                     }
981                 }
982             }
983         )+
984     };
985 }
986 
987 impl_try_into_number!( u8 u16 u32 u64 usize i8 i16 i32 i64 f64 );
988 
989 impl< E: Into< ConversionError >, V: TryFrom< Value, Error = E > > TryFrom< Value > for BTreeMap< String, V > {
990     type Error = ConversionError;
991 
992     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >993     fn try_from( value: Value ) -> Result< Self, Self::Error > {
994         match value {
995             Value::Reference( reference ) => {
996                 let object: Object = reference.try_into()?;
997                 object.try_into()
998             },
999             _ => {
1000                 let expected = match type_name_opt::< V >() {
1001                     Some( type_name ) => format!( "Object with values of type {}", type_name ).into(),
1002                     None => "Object".into()
1003                 };
1004 
1005                 Err( ConversionError::type_mismatch( &value, expected ) )
1006             }
1007         }
1008     }
1009 }
1010 
1011 impl< E: Into< ConversionError >, V: TryFrom< Value, Error = E > > TryFrom< Value > for HashMap< String, V > {
1012     type Error = ConversionError;
1013 
1014     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1015     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1016         match value {
1017             Value::Reference( reference ) => {
1018                 let object: Object = reference.try_into()?;
1019                 object.try_into()
1020             },
1021             _ => {
1022                 let expected = match type_name_opt::< V >() {
1023                     Some( type_name ) => format!( "Object with values of type {}", type_name ).into(),
1024                     None => "Object".into()
1025                 };
1026 
1027                 Err( ConversionError::type_mismatch( &value, expected ) )
1028             }
1029         }
1030     }
1031 }
1032 
1033 impl< E: Into< ConversionError >, T: TryFrom< Value, Error = E > > TryFrom< Value > for Vec< T > {
1034     type Error = ConversionError;
1035 
1036     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1037     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1038         match value {
1039             Value::Reference( reference ) => {
1040                 let array: Array = reference.try_into()?;
1041                 array.try_into()
1042             },
1043             _ => {
1044                 let expected = match type_name_opt::< T >() {
1045                     Some( type_name ) => format!( "Array with elements of type {}", type_name ).into(),
1046                     None => "Array".into()
1047                 };
1048 
1049                 Err( ConversionError::type_mismatch( &value, expected ) )
1050             }
1051         }
1052     }
1053 }
1054 
1055 impl TryFrom< Value > for String {
1056     type Error = ConversionError;
1057 
1058     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1059     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1060         match value {
1061             Value::String( value ) => Ok( value ),
1062             _ => Err( ConversionError::type_mismatch( &value, "String".into() ) )
1063         }
1064     }
1065 }
1066 
1067 impl TryFrom< Value > for Symbol {
1068     type Error = ConversionError;
1069 
1070     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1071     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1072         match value {
1073             Value::Symbol( value ) => Ok( value ),
1074             _ => Err( ConversionError::type_mismatch( &value, "Symbol".into() ) )
1075         }
1076     }
1077 }
1078 
1079 impl TryFrom< Value > for Reference {
1080     type Error = ConversionError;
1081 
1082     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1083     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1084         match value {
1085             Value::Reference( value ) => Ok( value ),
1086             _ => Err( ConversionError::type_mismatch( &value, "Reference".into() ) )
1087         }
1088     }
1089 }
1090 
1091 impl< 'a > TryFrom< &'a Value > for &'a str {
1092     type Error = ConversionError;
1093 
1094     #[inline]
try_from( value: &'a Value ) -> Result< Self, Self::Error >1095     fn try_from( value: &'a Value ) -> Result< Self, Self::Error > {
1096         match *value {
1097             Value::String( ref value ) => Ok( value ),
1098             _ => Err( ConversionError::type_mismatch( &value, "String".into() ) )
1099         }
1100     }
1101 }
1102 
1103 impl< 'a > TryFrom< &'a Value > for &'a Symbol {
1104     type Error = ConversionError;
1105 
1106     #[inline]
try_from( value: &'a Value ) -> Result< Self, Self::Error >1107     fn try_from( value: &'a Value ) -> Result< Self, Self::Error > {
1108         match *value {
1109             Value::Symbol( ref value ) => Ok( value ),
1110             _ => Err( ConversionError::type_mismatch( &value, "Symbol".into() ) )
1111         }
1112     }
1113 }
1114 
1115 impl< 'a > TryFrom< &'a Value > for &'a Reference {
1116     type Error = ConversionError;
1117 
1118     #[inline]
try_from( value: &'a Value ) -> Result< Self, Self::Error >1119     fn try_from( value: &'a Value ) -> Result< Self, Self::Error > {
1120         match *value {
1121             Value::Reference( ref value ) => Ok( value ),
1122             _ => Err( ConversionError::type_mismatch( &value, "Reference".into() ) )
1123         }
1124     }
1125 }
1126 
1127 macro_rules! __impl_nullable_try_from_value {
1128     (($($impl_arg:tt)*) ($($dst_arg:tt)*) ($($bounds:tt)*)) => {
1129         impl< $($impl_arg)* > TryFrom< Value > for Option< $($dst_arg)* > where $($bounds)* {
1130             type Error = ConversionError;
1131 
1132             #[inline]
1133             fn try_from( value: Value ) -> Result< Self, Self::Error > {
1134                 match value {
1135                     Value::Undefined | Value::Null => Ok( None ),
1136                     value => value.try_into().map( Some )
1137                 }
1138             }
1139         }
1140     };
1141 }
1142 
1143 macro_rules! impl_nullable_try_from_value {
1144     (impl< $($impl_arg:tt),* > $dst:ty where ($($bounds:tt)*); $($rest:tt)*) => {
1145         __impl_nullable_try_from_value!( ($($impl_arg),*) ($dst) ($($bounds)*) );
1146         impl_nullable_try_from_value!( $($rest)* );
1147     };
1148 
1149     (impl< $($impl_arg:tt),* > $dst:ty; $($rest:tt)*) => {
1150         __impl_nullable_try_from_value!( ($($impl_arg),*) ($dst) () );
1151         impl_nullable_try_from_value!( $($rest)* );
1152     };
1153 
1154     ($dst:ty; $($rest:tt)*) => {
1155         __impl_nullable_try_from_value!( () ($dst) () );
1156         impl_nullable_try_from_value!( $($rest)* );
1157 
1158     };
1159 
1160     () => {};
1161 }
1162 
1163 impl_nullable_try_from_value! {
1164     bool;
1165     u8;
1166     u16;
1167     u32;
1168     u64;
1169     usize;
1170     i8;
1171     i16;
1172     i32;
1173     i64;
1174     f64;
1175     impl< V > BTreeMap< String, V > where (V: TryFrom< Value, Error = ConversionError >);
1176     impl< V > HashMap< String, V > where (V: TryFrom< Value, Error = ConversionError >);
1177     impl< T > Vec< T > where (T: TryFrom< Value, Error = ConversionError >);
1178     String;
1179     Symbol;
1180 }
1181 
1182 impl< 'a > TryFrom< &'a Value > for Option< &'a str > {
1183     type Error = ConversionError;
1184 
1185     #[inline]
try_from( value: &'a Value ) -> Result< Self, Self::Error >1186     fn try_from( value: &'a Value ) -> Result< Self, Self::Error > {
1187         match *value {
1188             Value::String( ref value ) => Ok( Some( value ) ),
1189             ref value => value.try_into().map( Some )
1190         }
1191     }
1192 }
1193 
1194 impl< 'a > TryFrom< &'a Value > for Option< &'a Reference > {
1195     type Error = ConversionError;
1196 
1197     #[inline]
try_from( value: &'a Value ) -> Result< Self, Self::Error >1198     fn try_from( value: &'a Value ) -> Result< Self, Self::Error > {
1199         match *value {
1200             Value::Reference( ref value ) => Ok( Some( value ) ),
1201             ref value => value.try_into().map( Some )
1202         }
1203     }
1204 }
1205 
1206 impl< T: TryFrom< Value, Error = ConversionError > + AsRef< Reference > > TryFrom< Value > for Option< T > {
1207     type Error = ConversionError;
1208 
1209     #[inline]
try_from( value: Value ) -> Result< Self, Self::Error >1210     fn try_from( value: Value ) -> Result< Self, Self::Error > {
1211         match value {
1212             Value::Undefined | Value::Null => Ok( None ),
1213             value => value.try_into().map( Some )
1214         }
1215     }
1216 }
1217 
1218 #[cfg(test)]
1219 mod tests {
1220     use super::{Value, Reference, ConversionError};
1221     use webcore::try_from::TryInto;
1222 
1223     #[test]
string_equality()1224     fn string_equality() {
1225         let value = Value::String( "Hello!".to_owned() );
1226         assert!( value == "Hello!" );
1227         assert!( &value == "Hello!" );
1228         assert!( value == "Hello!".to_owned() );
1229         assert!( &value == "Hello!".to_owned() );
1230         assert!( value == &"Hello!".to_owned() );
1231         assert!( &value == &"Hello!".to_owned() );
1232         assert!( "Hello!" == value );
1233         assert!( "Hello!" == &value );
1234         assert!( "Hello!".to_owned() == value );
1235         assert!( "Hello!".to_owned() == &value );
1236         assert!( &"Hello!".to_owned() == value );
1237         assert!( &"Hello!".to_owned() == &value );
1238 
1239         assert!( value != "Bob" );
1240     }
1241 
1242     #[test]
reference_equality()1243     fn reference_equality() {
1244         let value = js! { return new Date() };
1245         let reference: Reference = value.clone().try_into().unwrap();
1246 
1247         assert!( value == reference );
1248         assert!( &value == reference );
1249         assert!( value == &reference );
1250         assert!( &value == &reference );
1251         assert!( reference == value );
1252         assert!( &reference == value );
1253         assert!( reference == &value );
1254         assert!( &reference == &value );
1255     }
1256 
1257     #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
1258     #[reference(instance_of = "Error")]
1259     pub struct Error( Reference );
1260 
1261     #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
1262     #[reference(instance_of = "ReferenceError")]
1263     #[reference(subclass_of(Error))]
1264     pub struct ReferenceError( Reference );
1265 
1266     #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
1267     #[reference(instance_of = "TypeError")]
1268     #[reference(subclass_of(Error))]
1269     pub struct TypeError( Reference );
1270 
1271     #[test]
reference_downcast()1272     fn reference_downcast() {
1273         let reference = js! { return new ReferenceError(); }.into_reference().unwrap();
1274         assert!( reference.clone().downcast::< Error >().is_some() );
1275         assert!( reference.clone().downcast::< ReferenceError >().is_some() );
1276         assert!( reference.clone().downcast::< TypeError >().is_none() );
1277     }
1278 
1279     #[test]
reference_try_into_downcast_from_reference()1280     fn reference_try_into_downcast_from_reference() {
1281         let reference = js! { return new ReferenceError(); }.into_reference().unwrap();
1282         let typed_reference: Result< Error, _ > = reference.clone().try_into();
1283         assert!( typed_reference.is_ok() );
1284 
1285         let typed_reference: Result< ReferenceError, _ > = reference.clone().try_into();
1286         assert!( typed_reference.is_ok() );
1287 
1288         let typed_reference: Result< TypeError, _ > = reference.clone().try_into();
1289         assert!( typed_reference.is_err() );
1290     }
1291 
1292     #[test]
reference_try_into_downcast_from_value()1293     fn reference_try_into_downcast_from_value() {
1294         let value = js! { return new ReferenceError(); };
1295         let typed_reference: Result< Error, _ > = value.clone().try_into();
1296         assert!( typed_reference.is_ok() );
1297 
1298         let typed_reference: Result< ReferenceError, _ > = value.clone().try_into();
1299         assert!( typed_reference.is_ok() );
1300 
1301         let typed_reference: Result< TypeError, _ > = value.clone().try_into();
1302         assert!( typed_reference.is_err() );
1303     }
1304 
1305     #[test]
reference_into_upcast()1306     fn reference_into_upcast() {
1307         let reference: ReferenceError = js! { return new ReferenceError(); }.into_reference().unwrap().downcast().unwrap();
1308         let _: Error = reference.clone().into();
1309         let _: Reference = reference.clone().into();
1310     }
1311 
1312     #[test]
reference_try_into_downcast_from_ref_value()1313     fn reference_try_into_downcast_from_ref_value() {
1314         let value = js! { return new ReferenceError(); };
1315         let value: &Value = &value;
1316 
1317         let typed_reference: Result< Error, _ > = value.try_into();
1318         assert!( typed_reference.is_ok() );
1319 
1320         let typed_reference: Result< ReferenceError, _ > = value.try_into();
1321         assert!( typed_reference.is_ok() );
1322 
1323         let typed_reference: Result< TypeError, _ > = value.try_into();
1324         assert!( typed_reference.is_err() );
1325     }
1326 
1327     #[test]
reference_try_into_downcast_from_ref_reference()1328     fn reference_try_into_downcast_from_ref_reference() {
1329         let reference: Reference = js! { return new ReferenceError(); }.try_into().unwrap();
1330         let reference: &Reference = &reference;
1331 
1332         let typed_reference: Result< Error, _ > = reference.try_into();
1333         assert!( typed_reference.is_ok() );
1334 
1335         let typed_reference: Result< ReferenceError, _ > = reference.try_into();
1336         assert!( typed_reference.is_ok() );
1337 
1338         let typed_reference: Result< TypeError, _ > = reference.try_into();
1339         assert!( typed_reference.is_err() );
1340     }
1341 
1342     #[test]
convert_from_null_or_undefined_to_empty_tuple()1343     fn convert_from_null_or_undefined_to_empty_tuple() {
1344         let a: Result< (), _ > = js! { return null; }.try_into();
1345         assert!( a.is_ok() );
1346 
1347         let a: Result< (), _ > = js! { return undefined; }.try_into();
1348         assert!( a.is_ok() );
1349 
1350         let a: Result< (), _ > = js! { return 1; }.try_into();
1351         assert!( a.is_err() );
1352     }
1353 
1354     #[test]
reference_stable()1355     fn reference_stable() {
1356         js! { Module.__test = {}; }
1357         let a = js! { return Module.__test; }.as_reference().unwrap().as_raw();
1358         let b = js! { return Module.__test; }.as_reference().unwrap().as_raw();
1359         assert_eq!(a, b);
1360 
1361         let c = js! { return {}; }.as_reference().unwrap().as_raw();
1362         assert_ne!(a, c);
1363 
1364         js! { delete Module.__test; }
1365     }
1366 
is_known_reference(refid: i32) -> bool1367     fn is_known_reference(refid: i32) -> bool {
1368         let has_refcount: bool = js! {
1369             return @{refid} in Module.STDWEB_PRIVATE.id_to_refcount_map;
1370         }.try_into().unwrap();
1371 
1372         let has_ref: bool = js! {
1373             return @{refid} in Module.STDWEB_PRIVATE.id_to_ref_map;
1374         }.try_into().unwrap();
1375 
1376         assert_eq!(has_refcount, has_ref);
1377         has_refcount
1378     }
1379 
1380     #[test]
reference_refcount()1381     fn reference_refcount() {
1382         let obj = js! { return new Object(); };
1383         let refid = obj.as_reference().unwrap().as_raw();
1384         assert!(is_known_reference(refid));
1385 
1386         drop(obj);
1387         assert!(!is_known_reference(refid));
1388     }
1389 
1390     #[test]
reference_refcount_clone()1391     fn reference_refcount_clone() {
1392         let obj = js! { return new Object(); };
1393         let obj2 = obj.clone();
1394 
1395         let refid = obj.as_reference().unwrap().as_raw();
1396         let refid2 = obj.as_reference().unwrap().as_raw();
1397 
1398         assert_eq!(refid, refid2);
1399         assert!(is_known_reference(refid));
1400 
1401         drop(obj);
1402         assert!(is_known_reference(refid));
1403 
1404         drop(obj2);
1405         assert!(!is_known_reference(refid));
1406     }
1407 
1408     #[test]
conversion_error_string_into_bool()1409     fn conversion_error_string_into_bool() {
1410         let a = Value::String( "Piggy".into() );
1411         let b: Result< bool, ConversionError > = a.try_into();
1412         assert_eq!(
1413             format!( "{}", b.unwrap_err() ),
1414             "type mismatch; expected bool, got String"
1415         );
1416     }
1417 
1418     #[cfg(rust_nightly)]
1419     #[test]
conversion_error_string_into_vec_of_bools()1420     fn conversion_error_string_into_vec_of_bools() {
1421         let a = Value::String( "Piggy".into() );
1422         let b: Result< Vec< bool >, ConversionError > = a.try_into();
1423         assert_eq!(
1424             format!( "{}", b.unwrap_err() ),
1425             "type mismatch; expected Array with elements of type bool, got String"
1426         );
1427     }
1428 }
1429