stdweb/webcore/
value.rs

1use std::collections::{BTreeMap, HashMap};
2use std::hash::Hash;
3use std::fmt;
4use std::error;
5use std::mem;
6use std::borrow::Cow;
7use webcore::void::Void;
8use webcore::try_from::{TryFrom, TryInto};
9use webcore::number::{self, Number};
10use webcore::object::Object;
11use webcore::array::Array;
12use webcore::serialization::JsSerialize;
13use webcore::reference_type::ReferenceType;
14use webcore::instance_of::InstanceOf;
15use webcore::symbol::Symbol;
16use webcore::type_name::type_name_opt;
17use webapi::error::TypeError;
18
19/// A unit type representing JavaScript's `undefined`.
20#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
21pub struct Undefined;
22
23/// A unit type representing JavaScript's `null`.
24#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)]
25pub struct Null;
26
27/// A type representing a reference to a JavaScript value.
28#[repr(C)]
29#[derive(Debug)]
30pub struct Reference( i32 );
31
32impl Reference {
33    #[doc(hidden)]
34    #[inline]
35    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]
42    pub(crate) unsafe fn from_raw_unchecked_noref( refid: i32 ) -> Reference {
43        Reference( refid )
44    }
45
46    #[doc(hidden)]
47    #[inline]
48    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]
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
64impl PartialEq for Reference {
65    #[inline]
66    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
78impl Eq for Reference {}
79
80impl Clone for Reference {
81    #[inline]
82    fn clone( &self ) -> Self {
83        unsafe {
84            Reference::from_raw_unchecked( self.as_raw() )
85        }
86    }
87}
88
89impl Drop for Reference {
90    #[inline]
91    fn drop( &mut self ) {
92        __js_raw_asm!( "Module.STDWEB_PRIVATE.decrement_refcount( $0 );", self.0 );
93    }
94}
95
96impl AsRef< Reference > for Reference {
97    #[inline]
98    fn as_ref( &self ) -> &Self {
99        self
100    }
101}
102
103macro_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
116macro_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
136impl_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)]
161pub enum Value {
162    Undefined,
163    Null,
164    Bool( bool ),
165    Number( Number ),
166    Symbol( Symbol ),
167    String( String ),
168    Reference( Reference )
169}
170
171impl Value {
172    /// Checks whenever the Value is of the Null variant.
173    #[inline]
174    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]
184    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]
194    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]
204    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]
214    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]
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]
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]
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]
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]
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]
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]
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]
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]
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
313impl AsRef< Value > for Value {
314    #[inline]
315    fn as_ref( &self ) -> &Self {
316        self
317    }
318}
319
320impl From< Undefined > for Value {
321    #[inline]
322    fn from( _: Undefined ) -> Self {
323        Value::Undefined
324    }
325}
326
327impl< 'a > From< &'a Undefined > for Value {
328    #[inline]
329    fn from( _: &'a Undefined ) -> Self {
330        Value::Undefined
331    }
332}
333
334impl< 'a > From< &'a mut Undefined > for Value {
335    #[inline]
336    fn from( _: &'a mut Undefined ) -> Self {
337        Value::Undefined
338    }
339}
340
341impl From< Null > for Value {
342    #[inline]
343    fn from( _: Null ) -> Self {
344        Value::Null
345    }
346}
347
348impl< 'a > From< &'a Null > for Value {
349    #[inline]
350    fn from( _: &'a Null ) -> Self {
351        Value::Null
352    }
353}
354
355impl< 'a > From< &'a mut Null > for Value {
356    #[inline]
357    fn from( _: &'a mut Null ) -> Self {
358        Value::Null
359    }
360}
361
362impl From< bool > for Value {
363    #[inline]
364    fn from( value: bool ) -> Self {
365        Value::Bool( value )
366    }
367}
368
369impl< 'a > From< &'a bool > for Value {
370    #[inline]
371    fn from( value: &'a bool ) -> Self {
372        Value::Bool( *value )
373    }
374}
375
376impl< 'a > From< &'a mut bool > for Value {
377    #[inline]
378    fn from( value: &'a mut bool ) -> Self {
379        (value as &bool).into()
380    }
381}
382
383impl< 'a > From< &'a str > for Value {
384    #[inline]
385    fn from( value: &'a str ) -> Self {
386        Value::String( value.to_string() )
387    }
388}
389
390impl< 'a > From< &'a mut str > for Value {
391    #[inline]
392    fn from( value: &'a mut str ) -> Self {
393        (value as &str).into()
394    }
395}
396
397impl From< String > for Value {
398    #[inline]
399    fn from( value: String ) -> Self {
400        Value::String( value )
401    }
402}
403
404impl< 'a > From< &'a String > for Value {
405    #[inline]
406    fn from( value: &'a String ) -> Self {
407        Value::String( value.clone() )
408    }
409}
410
411impl< 'a > From< &'a mut String > for Value {
412    #[inline]
413    fn from( value: &'a mut String ) -> Self {
414        (value as &String).into()
415    }
416}
417
418impl From< char > for Value {
419    #[inline]
420    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
427impl< 'a > From< &'a char > for Value {
428    #[inline]
429    fn from( value: &'a char ) -> Self {
430        (*value).into()
431    }
432}
433
434impl< 'a > From< &'a mut char > for Value {
435    #[inline]
436    fn from( value: &'a mut char ) -> Self {
437        (*value).into()
438    }
439}
440
441impl< T > From< Vec< T > > for Value where T: JsSerialize {
442    #[inline]
443    fn from( value: Vec< T > ) -> Self {
444        value[..].into()
445    }
446}
447
448impl< 'a, T > From< &'a Vec< T > > for Value where T: JsSerialize {
449    #[inline]
450    fn from( value: &'a Vec< T > ) -> Self {
451        value[..].into()
452    }
453}
454
455impl< 'a, T > From< &'a mut Vec< T > > for Value where T: JsSerialize {
456    #[inline]
457    fn from( value: &'a mut Vec< T > ) -> Self {
458        value[..].into()
459    }
460}
461
462impl< 'a, T > From< &'a [T] > for Value where T: JsSerialize {
463    #[inline]
464    fn from( value: &'a [T] ) -> Self {
465        let array: Array = value.into();
466        Value::Reference( array.into() )
467    }
468}
469
470impl< 'a, T > From< &'a mut [T] > for Value where T: JsSerialize {
471    #[inline]
472    fn from( value: &'a mut [T] ) -> Self {
473        (value as &[T]).into()
474    }
475}
476
477impl< K, V > From< BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
478    #[inline]
479    fn from( value: BTreeMap< K, V > ) -> Self {
480        let object: Object = value.into();
481        Value::Reference( object.into() )
482    }
483}
484
485impl< 'a, K, V > From< &'a BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
486    #[inline]
487    fn from( value: &'a BTreeMap< K, V > ) -> Self {
488        let object: Object = value.into();
489        Value::Reference( object.into() )
490    }
491}
492
493impl< 'a, K, V > From< &'a mut BTreeMap< K, V > > for Value where K: AsRef< str >, V: JsSerialize {
494    #[inline]
495    fn from( value: &'a mut BTreeMap< K, V > ) -> Self {
496        let object: Object = value.into();
497        Value::Reference( object.into() )
498    }
499}
500
501impl< K, V > From< HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
502    #[inline]
503    fn from( value: HashMap< K, V > ) -> Self {
504        let object: Object = value.into();
505        Value::Reference( object.into() )
506    }
507}
508
509impl< 'a, K, V > From< &'a HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
510    #[inline]
511    fn from( value: &'a HashMap< K, V > ) -> Self {
512        let object: Object = value.into();
513        Value::Reference( object.into() )
514    }
515}
516
517impl< 'a, K, V > From< &'a mut HashMap< K, V > > for Value where K: AsRef< str > + Eq + Hash, V: JsSerialize {
518    #[inline]
519    fn from( value: &'a mut HashMap< K, V > ) -> Self {
520        let object: Object = value.into();
521        Value::Reference( object.into() )
522    }
523}
524
525impl From< Reference > for Value {
526    #[inline]
527    fn from( value: Reference ) -> Self {
528        Value::Reference( value )
529    }
530}
531
532impl< 'a > From< &'a Reference > for Value {
533    #[inline]
534    fn from( value: &'a Reference ) -> Self {
535        Value::Reference( value.clone() )
536    }
537}
538
539impl< 'a > From< &'a mut Reference > for Value {
540    #[inline]
541    fn from( value: &'a mut Reference ) -> Self {
542        (value as &Reference).into()
543    }
544}
545
546macro_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
575impl_from_number!( i8 i16 i32 u8 u16 u32 f32 f64 );
576impl_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
627macro_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
642impl_try_from_number!( i64 u64 usize );
643
644impl PartialEq< Undefined > for Value {
645    #[inline]
646    fn eq( &self, _: &Undefined ) -> bool {
647        match *self {
648            Value::Undefined => true,
649            _ => false
650        }
651    }
652}
653
654impl PartialEq< Null > for Value {
655    #[inline]
656    fn eq( &self, _: &Null ) -> bool {
657        match *self {
658            Value::Null => true,
659            _ => false
660        }
661    }
662}
663
664impl PartialEq< bool > for Value {
665    #[inline]
666    fn eq( &self, right: &bool ) -> bool {
667        match *self {
668            Value::Bool( left ) => left == *right,
669            _ => false
670        }
671    }
672}
673
674impl PartialEq< str > for Value {
675    #[inline]
676    fn eq( &self, right: &str ) -> bool {
677        match *self {
678            Value::String( ref left ) => left == right,
679            _ => false
680        }
681    }
682}
683
684impl PartialEq< String > for Value {
685    #[inline]
686    fn eq( &self, right: &String ) -> bool {
687        match *self {
688            Value::String( ref left ) => left == right,
689            _ => false
690        }
691    }
692}
693
694impl PartialEq< Number > for Value {
695    #[inline]
696    fn eq( &self, right: &Number ) -> bool {
697        match *self {
698            Value::Number( left ) => left == *right,
699            _ => false
700        }
701    }
702}
703
704impl PartialEq< Symbol > for Value {
705    #[inline]
706    fn eq( &self, right: &Symbol ) -> bool {
707        match *self {
708            Value::Symbol( ref left ) => *left == *right,
709            _ => false
710        }
711    }
712}
713
714impl< T: AsRef< Reference > > PartialEq< T > for Value {
715    #[inline]
716    fn eq( &self, right: &T ) -> bool {
717        match *self {
718            Value::Reference( ref left ) => left == right.as_ref(),
719            _ => false
720        }
721    }
722}
723
724impl< 'a > PartialEq< Reference > for &'a Value {
725    #[inline]
726    fn eq( &self, right: &Reference ) -> bool {
727        (*self).eq( right )
728    }
729}
730
731impl PartialEq< Value > for Reference {
732    #[inline]
733    fn eq( &self, right: &Value ) -> bool {
734        right.eq( self )
735    }
736}
737
738impl< 'a > PartialEq< &'a Value > for Reference {
739    #[inline]
740    fn eq( &self, right: &&'a Value ) -> bool {
741        let right: &'a Value = right;
742        right.eq( self )
743    }
744}
745
746impl< 'a > PartialEq< Value > for &'a Reference {
747    #[inline]
748    fn eq( &self, right: &Value ) -> bool {
749        (*self).eq( right )
750    }
751}
752
753macro_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
796macro_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
814impl_partial_eq_to_number!( i8 i16 i32 i64 u8 u16 u32 u64 usize f32 f64 );
815
816impl_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)]
830pub 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
840fn 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
852impl fmt::Display for ConversionError {
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
865impl error::Error for ConversionError {
866    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
876impl From< number::ConversionError > for ConversionError {
877    fn from( inner: number::ConversionError ) -> Self {
878        ConversionError::NumericConversionError( inner )
879    }
880}
881
882impl From< Void > for ConversionError {
883    fn from( _: Void ) -> Self {
884        unreachable!();
885    }
886}
887
888impl From< ConversionError > for TypeError {
889    fn from( error: ConversionError ) -> TypeError {
890        (&error).into()
891    }
892}
893
894impl< 'a > From< &'a ConversionError > for TypeError {
895    fn from( error: &'a ConversionError ) -> TypeError {
896        js!( return new TypeError( @{format!( "{}", error )} ); ).try_into().unwrap()
897    }
898}
899
900impl ConversionError {
901    #[inline]
902    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]
910    pub(crate) fn value_conversion_error( inner: ConversionError ) -> Self {
911        ConversionError::ValueConversionError( Box::new( inner ) )
912    }
913}
914
915impl TryFrom< Value > for Undefined {
916    type Error = ConversionError;
917
918    #[inline]
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
927impl TryFrom< Value > for Null {
928    type Error = ConversionError;
929
930    #[inline]
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
939impl TryFrom< Value > for () {
940    type Error = ConversionError;
941
942    #[inline]
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
951impl TryFrom< Value > for bool {
952    type Error = ConversionError;
953
954    #[inline]
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
963macro_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
987impl_try_into_number!( u8 u16 u32 u64 usize i8 i16 i32 i64 f64 );
988
989impl< E: Into< ConversionError >, V: TryFrom< Value, Error = E > > TryFrom< Value > for BTreeMap< String, V > {
990    type Error = ConversionError;
991
992    #[inline]
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
1011impl< E: Into< ConversionError >, V: TryFrom< Value, Error = E > > TryFrom< Value > for HashMap< String, V > {
1012    type Error = ConversionError;
1013
1014    #[inline]
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
1033impl< E: Into< ConversionError >, T: TryFrom< Value, Error = E > > TryFrom< Value > for Vec< T > {
1034    type Error = ConversionError;
1035
1036    #[inline]
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
1055impl TryFrom< Value > for String {
1056    type Error = ConversionError;
1057
1058    #[inline]
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
1067impl TryFrom< Value > for Symbol {
1068    type Error = ConversionError;
1069
1070    #[inline]
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
1079impl TryFrom< Value > for Reference {
1080    type Error = ConversionError;
1081
1082    #[inline]
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
1091impl< 'a > TryFrom< &'a Value > for &'a str {
1092    type Error = ConversionError;
1093
1094    #[inline]
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
1103impl< 'a > TryFrom< &'a Value > for &'a Symbol {
1104    type Error = ConversionError;
1105
1106    #[inline]
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
1115impl< 'a > TryFrom< &'a Value > for &'a Reference {
1116    type Error = ConversionError;
1117
1118    #[inline]
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
1127macro_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
1143macro_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
1163impl_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
1182impl< 'a > TryFrom< &'a Value > for Option< &'a str > {
1183    type Error = ConversionError;
1184
1185    #[inline]
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
1194impl< 'a > TryFrom< &'a Value > for Option< &'a Reference > {
1195    type Error = ConversionError;
1196
1197    #[inline]
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
1206impl< T: TryFrom< Value, Error = ConversionError > + AsRef< Reference > > TryFrom< Value > for Option< T > {
1207    type Error = ConversionError;
1208
1209    #[inline]
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)]
1219mod tests {
1220    use super::{Value, Reference, ConversionError};
1221    use webcore::try_from::TryInto;
1222
1223    #[test]
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]
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]
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]
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]
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]
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]
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]
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]
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]
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
1367    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]
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]
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]
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]
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}