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