stdweb/webcore/
serialization.rs

1use std::mem;
2use std::slice;
3use std::i32;
4use std::collections::{BTreeMap, HashMap};
5use std::marker::PhantomData;
6use std::hash::Hash;
7use std::ops::Deref;
8
9use webcore::ffi;
10use webcore::callfn::{CallOnce, CallMut};
11use webcore::newtype::Newtype;
12use webcore::try_from::{TryFrom, TryInto};
13use webcore::number::Number;
14use webcore::type_name::type_name;
15use webcore::symbol::Symbol;
16use webcore::unsafe_typed_array::UnsafeTypedArray;
17use webcore::mutfn::Mut;
18use webcore::once::Once;
19use webcore::global_arena;
20use webcore::optional_arg::OptionalArg;
21
22use webcore::value::{
23    Null,
24    Undefined,
25    Reference,
26    Value,
27    ConversionError
28};
29
30use webapi::error::TypeError;
31
32#[repr(u8)]
33#[derive(Copy, Clone, PartialEq, Debug)]
34pub enum Tag {
35    Undefined = 0,
36    Null = 1,
37    I32 = 2,
38    F64 = 3,
39    Str = 4,
40    False = 5,
41    True = 6,
42    Array = 7,
43    Object = 8,
44    Reference = 9,
45    Function = 10,
46    FunctionMut = 12,
47    FunctionOnce = 13,
48    UnsafeTypedArray = 14,
49    Symbol = 15
50}
51
52impl Default for Tag {
53    #[inline]
54    fn default() -> Self {
55        Tag::Undefined
56    }
57}
58
59#[doc(hidden)]
60pub trait JsSerializeOwned: Sized {
61    fn into_js_owned< 'a >( value: &'a mut Option< Self > ) -> SerializedValue< 'a >;
62}
63
64/// A trait for types which can be serialized through the `js!` macro.
65///
66/// Do **not** try to implement this trait yourself! It's only meant
67/// to be used inside generic code for specifying trait bounds.
68pub trait JsSerialize {
69    #[doc(hidden)]
70    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a >;
71}
72
73// This is a generic structure for serializing every JavaScript value.
74#[doc(hidden)]
75#[repr(C)]
76#[derive(Default, Debug)]
77pub struct SerializedValue< 'a > {
78    data_1: u64,
79    data_2: u32,
80    tag: Tag,
81    phantom: PhantomData< &'a () >
82}
83
84#[test]
85fn test_serialized_value_size() {
86    assert_eq!( mem::size_of::< SerializedValue< 'static > >(), 16 );
87}
88
89#[repr(C)]
90#[derive(Debug)]
91struct SerializedUntaggedUndefined;
92
93#[repr(C)]
94#[derive(Debug)]
95struct SerializedUntaggedNull;
96
97#[repr(C)]
98#[derive(Debug)]
99struct SerializedUntaggedI32 {
100    value: i32
101}
102
103#[repr(C)]
104#[derive(Debug)]
105struct SerializedUntaggedF64 {
106    value: f64
107}
108
109#[repr(C)]
110#[derive(Debug)]
111struct SerializedUntaggedTrue {}
112
113#[repr(C)]
114#[derive(Debug)]
115struct SerializedUntaggedFalse {}
116
117#[repr(C)]
118#[derive(Clone, Debug)]
119struct SerializedUntaggedString {
120    pointer: u32,
121    length: u32
122}
123
124#[repr(C)]
125#[derive(Clone, Debug)]
126struct SerializedUntaggedArray {
127    pointer: u32,
128    length: u32
129}
130
131#[repr(C)]
132#[derive(Debug)]
133struct SerializedUntaggedObject {
134    value_pointer: u32,
135    length: u32,
136    key_pointer: u32
137}
138
139#[repr(C)]
140#[derive(Debug)]
141struct SerializedUntaggedSymbol {
142    id: i32
143}
144
145#[repr(C)]
146#[derive(Debug)]
147struct SerializedUntaggedReference {
148    refid: i32
149}
150
151#[repr(C)]
152#[derive(Debug)]
153struct SerializedUntaggedFunction {
154    adapter_pointer: u32,
155    pointer: u32,
156    deallocator_pointer: u32
157}
158
159#[repr(C)]
160#[derive(Debug)]
161struct SerializedUntaggedFunctionMut {
162    adapter_pointer: u32,
163    pointer: u32,
164    deallocator_pointer: u32
165}
166
167#[repr(C)]
168#[derive(Debug)]
169struct SerializedUntaggedFunctionOnce {
170    adapter_pointer: u32,
171    pointer: u32,
172    deallocator_pointer: u32
173}
174
175#[repr(C)]
176#[derive(Debug)]
177struct SerializedUntaggedUnsafeTypedArray {
178    pointer: u32,
179    length: u32,
180    kind: u32
181}
182
183impl SerializedUntaggedString {
184    #[inline]
185    fn deserialize( &self ) -> String {
186        let pointer = self.pointer as *mut u8;
187        let length = self.length as usize;
188
189        if length == 0 {
190            return String::new();
191        }
192
193        unsafe {
194            let vector = Vec::from_raw_parts( pointer, length, length + 1 );
195            String::from_utf8_unchecked( vector )
196        }
197    }
198}
199
200impl SerializedUntaggedArray {
201    #[inline]
202    fn deserialize( &self ) -> Vec< Value > {
203        let pointer = self.pointer as *const SerializedValue;
204        let length = self.length as usize;
205        let slice = unsafe {
206            slice::from_raw_parts( pointer, length )
207        };
208
209        let vector = slice.iter().map( |value| value.deserialize() ).collect();
210        unsafe {
211            ffi::dealloc( pointer as *mut u8, length * mem::size_of::< SerializedValue >() );
212        }
213
214        vector
215    }
216}
217
218/// Owns some memory allocated by FFI, and will deallocate it on drop.
219///
220/// `T` must not be zero-sized.
221struct OwnedFfiSlice< T > {
222    ptr: *const T,
223    length: usize,
224}
225
226impl< T > OwnedFfiSlice< T > {
227    unsafe fn new(ptr: *const T, length: usize) -> Self {
228        assert_ne!( mem::size_of::< T >(), 0 );
229        OwnedFfiSlice { ptr, length }
230    }
231}
232
233impl< T > Deref for OwnedFfiSlice< T > {
234    type Target = [ T ];
235
236    fn deref( &self ) -> & [ T ] {
237        assert_ne!( mem::size_of::< T >(), 0 );
238        unsafe { slice::from_raw_parts ( self.ptr, self.length ) }
239    }
240}
241
242impl< T > Drop for OwnedFfiSlice< T >  {
243    fn drop( &mut self ) {
244        assert_ne!( mem::size_of::< T >(), 0 );
245        unsafe {
246            ffi::dealloc( self.ptr as *mut u8, self.length * mem::size_of::< T >() );
247        }
248    }
249}
250
251pub struct ObjectDeserializer {
252    key_slice: OwnedFfiSlice < SerializedUntaggedString >,
253    value_slice: OwnedFfiSlice < SerializedValue< 'static > >,
254    index: usize
255}
256
257impl Drop for ObjectDeserializer {
258    fn drop( &mut self ) {
259        // ensure that if this is dropped early, all the strings and any
260        // allocated values are deserialized and then dropped.
261        self.for_each( drop );
262    }
263}
264
265impl Iterator for ObjectDeserializer {
266    type Item = (String, Value);
267    fn next( &mut self ) -> Option< Self::Item > {
268        if self.index >= self.key_slice.len() {
269            None
270        } else {
271            let key = self.key_slice[ self.index ].deserialize();
272            let value = self.value_slice[ self.index ].deserialize();
273            self.index += 1;
274            Some( (key, value) )
275        }
276    }
277
278    #[inline]
279    fn size_hint( &self ) -> (usize, Option< usize >) {
280        let remaining = self.key_slice.len() - self.index;
281        (remaining, Some( remaining ))
282    }
283}
284
285impl ExactSizeIterator for ObjectDeserializer {}
286
287pub fn deserialize_object_to_iter( reference: &Reference ) -> ObjectDeserializer {
288    let mut result: SerializedValue = Default::default();
289    __js_raw_asm!( "\
290        var object = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );\
291        Module.STDWEB_PRIVATE.serialize_object( $1, object );",
292        reference.as_raw(),
293        &mut result as *mut _
294    );
295
296    assert_eq!( result.tag, Tag::Object );
297    let result = result.as_object();
298
299    let length = result.length as usize;
300    let key_pointer = result.key_pointer as *const SerializedUntaggedString;
301    let value_pointer = result.value_pointer as *const SerializedValue;
302
303    // These structs will drop the FFI allocated slices when they're dropped
304    //
305    // The ObjectDeserializer will also iterate itself to completion on drop, to ensure
306    // the strings and any allocated values are dropped and correctly deallocated.
307    let key_slice = unsafe { OwnedFfiSlice::new( key_pointer, length ) };
308    let value_slice = unsafe { OwnedFfiSlice::new( value_pointer, length ) };
309
310    ObjectDeserializer {
311        key_slice,
312        value_slice,
313        index: 0
314    }
315}
316
317pub fn deserialize_object< R, F: FnOnce( &mut ObjectDeserializer ) -> R >( reference: &Reference, callback: F ) -> R {
318    let mut iter = deserialize_object_to_iter( reference );
319
320    let output = callback( &mut iter );
321
322    drop(iter);
323
324    output
325}
326
327pub struct ArrayDeserializer< 'a > {
328    slice: &'a [SerializedValue< 'a >],
329    index: usize
330}
331
332impl< 'a > Iterator for ArrayDeserializer< 'a > {
333    type Item = Value;
334    fn next( &mut self ) -> Option< Self::Item > {
335        if self.index >= self.slice.len() {
336            None
337        } else {
338            let value = self.slice[ self.index ].deserialize();
339            self.index += 1;
340            Some( value )
341        }
342    }
343
344    #[inline]
345    fn size_hint( &self ) -> (usize, Option< usize >) {
346        let remaining = self.slice.len() - self.index;
347        (remaining, Some( remaining ))
348    }
349}
350
351impl< 'a > ExactSizeIterator for ArrayDeserializer< 'a > {}
352
353pub fn deserialize_array< R, F: FnOnce( &mut ArrayDeserializer ) -> R >( reference: &Reference, callback: F ) -> R {
354    let mut result: SerializedValue = Default::default();
355    __js_raw_asm!( "\
356        var array = Module.STDWEB_PRIVATE.acquire_js_reference( $0 );\
357        Module.STDWEB_PRIVATE.serialize_array( $1, array );",
358        reference.as_raw(),
359        &mut result as *mut _
360    );
361
362    assert_eq!( result.tag, Tag::Array );
363    let result = result.as_array();
364
365    let length = result.length as usize;
366    let pointer = result.pointer as *const SerializedValue;
367
368    let slice = unsafe { slice::from_raw_parts( pointer, length ) };
369    let mut iter = ArrayDeserializer {
370        slice,
371        index: 0
372    };
373
374    let output = callback( &mut iter );
375
376    // TODO: Panic-safety.
377    unsafe {
378        ffi::dealloc( pointer as *mut u8, length * mem::size_of::< SerializedValue >() );
379    }
380
381    output
382}
383
384impl SerializedUntaggedSymbol {
385    #[inline]
386    fn deserialize( &self ) -> Symbol {
387        Symbol( self.id )
388    }
389}
390
391impl SerializedUntaggedReference {
392    #[inline]
393    fn deserialize( &self ) -> Reference {
394        unsafe { Reference::from_raw_unchecked_noref( self.refid ) }
395    }
396}
397
398macro_rules! untagged_boilerplate {
399    ($tests_namespace:ident, $reader_name:ident, $tag:expr, $untagged_type:ident) => {
400        impl< 'a > SerializedValue< 'a > {
401            #[allow(dead_code)]
402            #[inline]
403            fn $reader_name( &self ) -> &$untagged_type {
404                debug_assert_eq!( self.tag, $tag );
405                unsafe {
406                    &*(self as *const _ as *const $untagged_type)
407                }
408            }
409        }
410
411        impl< 'a > From< $untagged_type > for SerializedValue< 'a > {
412            #[inline]
413            fn from( untagged: $untagged_type ) -> Self {
414                unsafe {
415                    let mut value: SerializedValue = mem::uninitialized();
416                    *(&mut value as *mut SerializedValue as *mut $untagged_type) = untagged;
417                    value.tag = $tag;
418                    value
419                }
420            }
421        }
422
423        #[cfg(test)]
424        mod $tests_namespace {
425            use super::*;
426
427            #[test]
428            fn does_not_overlap_with_the_tag() {
429                let size = mem::size_of::< $untagged_type >();
430                let tag_offset = unsafe { &(&*(0 as *const SerializedValue< 'static >)).tag as *const _ as usize };
431                assert!( size <= tag_offset );
432            }
433        }
434    }
435}
436
437untagged_boilerplate!( test_undefined, as_undefined, Tag::Undefined, SerializedUntaggedUndefined );
438untagged_boilerplate!( test_null, as_null, Tag::Null, SerializedUntaggedNull );
439untagged_boilerplate!( test_i32, as_i32, Tag::I32, SerializedUntaggedI32 );
440untagged_boilerplate!( test_f64, as_f64, Tag::F64, SerializedUntaggedF64 );
441untagged_boilerplate!( test_true, as_true, Tag::True, SerializedUntaggedTrue );
442untagged_boilerplate!( test_false, as_false, Tag::False, SerializedUntaggedFalse );
443untagged_boilerplate!( test_object, as_object, Tag::Object, SerializedUntaggedObject );
444untagged_boilerplate!( test_string, as_string, Tag::Str, SerializedUntaggedString );
445untagged_boilerplate!( test_array, as_array, Tag::Array, SerializedUntaggedArray );
446untagged_boilerplate!( test_symbol, as_symbol, Tag::Symbol, SerializedUntaggedSymbol );
447untagged_boilerplate!( test_reference, as_reference, Tag::Reference, SerializedUntaggedReference );
448untagged_boilerplate!( test_function, as_function, Tag::Function, SerializedUntaggedFunction );
449untagged_boilerplate!( test_function_mut, as_function_mut, Tag::FunctionMut, SerializedUntaggedFunctionMut );
450untagged_boilerplate!( test_function_once, as_function_once, Tag::FunctionOnce, SerializedUntaggedFunctionOnce );
451untagged_boilerplate!( test_unsafe_typed_array, as_unsafe_typed_array, Tag::UnsafeTypedArray, SerializedUntaggedUnsafeTypedArray );
452
453impl< 'a > SerializedValue< 'a > {
454    #[doc(hidden)]
455    #[inline]
456    pub fn deserialize( &self ) -> Value {
457        match self.tag {
458            Tag::Undefined => Value::Undefined,
459            Tag::Null => Value::Null,
460            Tag::I32 => self.as_i32().value.into(),
461            Tag::F64 => self.as_f64().value.into(),
462            Tag::Str => Value::String( self.as_string().deserialize() ),
463            Tag::False => Value::Bool( false ),
464            Tag::True => Value::Bool( true ),
465            Tag::Reference => self.as_reference().deserialize().into(),
466            Tag::Symbol => self.as_symbol().deserialize().into(),
467            Tag::Function |
468            Tag::FunctionMut |
469            Tag::FunctionOnce |
470            Tag::Object |
471            Tag::Array |
472            Tag::UnsafeTypedArray => unreachable!()
473        }
474    }
475}
476
477impl JsSerialize for () {
478    #[doc(hidden)]
479    #[inline]
480    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
481        SerializedUntaggedUndefined.into()
482    }
483}
484
485__js_serializable_boilerplate!( () );
486
487impl JsSerialize for Undefined {
488    #[doc(hidden)]
489    #[inline]
490    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
491        SerializedUntaggedUndefined.into()
492    }
493}
494
495__js_serializable_boilerplate!( Undefined );
496
497impl JsSerialize for Null {
498    #[doc(hidden)]
499    #[inline]
500    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
501        SerializedUntaggedNull.into()
502    }
503}
504
505__js_serializable_boilerplate!( Null );
506
507impl JsSerialize for Symbol {
508    #[doc(hidden)]
509    #[inline]
510    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
511        SerializedUntaggedSymbol {
512            id: self.0
513        }.into()
514    }
515}
516
517__js_serializable_boilerplate!( Symbol );
518
519impl JsSerialize for Reference {
520    #[doc(hidden)]
521    #[inline]
522    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
523        SerializedUntaggedReference {
524            refid: self.as_raw()
525        }.into()
526    }
527}
528
529__js_serializable_boilerplate!( Reference );
530
531impl JsSerialize for bool {
532    #[doc(hidden)]
533    #[inline]
534    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
535        if *self {
536            SerializedUntaggedTrue {}.into()
537        } else {
538            SerializedUntaggedFalse {}.into()
539        }
540    }
541}
542
543__js_serializable_boilerplate!( bool );
544
545impl JsSerialize for str {
546    #[doc(hidden)]
547    #[inline]
548    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
549        SerializedUntaggedString {
550            pointer: self.as_ptr() as u32,
551            length: self.len() as u32
552        }.into()
553    }
554}
555
556__js_serializable_boilerplate!( impl< 'a > for &'a str );
557
558impl JsSerialize for String {
559    #[doc(hidden)]
560    #[inline]
561    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
562        self.as_str()._into_js()
563    }
564}
565
566__js_serializable_boilerplate!( String );
567
568impl JsSerialize for i8 {
569    #[doc(hidden)]
570    #[inline]
571    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
572        SerializedUntaggedI32 {
573            value: *self as i32
574        }.into()
575    }
576}
577
578__js_serializable_boilerplate!( i8 );
579
580impl JsSerialize for i16 {
581    #[doc(hidden)]
582    #[inline]
583    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
584        SerializedUntaggedI32 {
585            value: *self as i32
586        }.into()
587    }
588}
589
590__js_serializable_boilerplate!( i16 );
591
592impl JsSerialize for i32 {
593    #[doc(hidden)]
594    #[inline]
595    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
596        SerializedUntaggedI32 {
597            value: *self
598        }.into()
599    }
600}
601
602__js_serializable_boilerplate!( i32 );
603
604impl JsSerialize for u8 {
605    #[doc(hidden)]
606    #[inline]
607    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
608        SerializedUntaggedI32 {
609            value: *self as i32
610        }.into()
611    }
612}
613
614__js_serializable_boilerplate!( u8 );
615
616impl JsSerialize for u16 {
617    #[doc(hidden)]
618    #[inline]
619    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
620        SerializedUntaggedI32 {
621            value: *self as i32
622        }.into()
623    }
624}
625
626__js_serializable_boilerplate!( u16 );
627
628impl JsSerialize for u32 {
629    #[doc(hidden)]
630    #[inline]
631    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
632        SerializedUntaggedF64 {
633            value: *self as f64
634        }.into()
635    }
636}
637
638__js_serializable_boilerplate!( u32 );
639
640impl JsSerialize for f32 {
641    #[doc(hidden)]
642    #[inline]
643    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
644        SerializedUntaggedF64 {
645            value: *self as f64
646        }.into()
647    }
648}
649
650__js_serializable_boilerplate!( f32 );
651
652impl JsSerialize for f64 {
653    #[doc(hidden)]
654    #[inline]
655    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
656        SerializedUntaggedF64 {
657            value: *self
658        }.into()
659    }
660}
661
662__js_serializable_boilerplate!( f64 );
663
664impl JsSerialize for Number {
665    #[doc(hidden)]
666    #[inline]
667    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
668        use webcore::number::{Storage, get_storage};
669        match *get_storage( self ) {
670            Storage::I32( ref value ) => value._into_js(),
671            Storage::F64( ref value ) => value._into_js()
672        }
673    }
674}
675
676__js_serializable_boilerplate!( Number );
677
678impl< T: JsSerialize > JsSerialize for Option< T > {
679    #[doc(hidden)]
680    #[inline]
681    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
682        if let Some( value ) = self.as_ref() {
683            value._into_js()
684        } else {
685            SerializedUntaggedNull.into()
686        }
687    }
688}
689
690__js_serializable_boilerplate!( impl< T > for Option< T > where T: JsSerialize );
691
692impl< T: JsSerialize > JsSerialize for OptionalArg< T > {
693    #[doc(hidden)]
694    #[inline]
695    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
696        if let OptionalArg::Some( value ) = self.as_ref() {
697            value._into_js()
698        } else {
699            SerializedUntaggedUndefined.into()
700        }
701    }
702}
703
704__js_serializable_boilerplate!( impl< T > for OptionalArg< T > where T: JsSerialize );
705
706impl< T: JsSerialize > JsSerialize for [T] {
707    #[doc(hidden)]
708    #[inline]
709    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
710        let mut output = global_arena::reserve( self.len() );
711        for value in self {
712            unsafe {
713                output.append( value._into_js() );
714            }
715        }
716
717        SerializedUntaggedArray {
718            pointer: output.offset() as u32,
719            length: output.len() as u32
720        }.into()
721    }
722}
723
724__js_serializable_boilerplate!( impl< 'a, T > for &'a [T] where T: JsSerialize );
725
726impl< T: JsSerialize > JsSerialize for Vec< T > {
727    #[doc(hidden)]
728    #[inline]
729    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
730        self.as_slice()._into_js()
731    }
732}
733
734__js_serializable_boilerplate!( impl< T > for Vec< T > where T: JsSerialize );
735
736fn object_into_js< 'a, K: AsRef< str >, V: 'a + JsSerialize, I: Iterator< Item = (K, &'a V) > + ExactSizeIterator >( iter: I ) -> SerializedValue< 'a > {
737    let mut keys = global_arena::reserve( iter.len() );
738    let mut values = global_arena::reserve( iter.len() );
739    for (key, value) in iter {
740        unsafe {
741            keys.append( key.as_ref()._into_js().as_string().clone() );
742            values.append( value._into_js() );
743        }
744    }
745
746    SerializedUntaggedObject {
747        key_pointer: keys.offset() as u32,
748        value_pointer: values.offset() as u32,
749        length: keys.len() as u32
750    }.into()
751}
752
753impl< K: AsRef< str >, V: JsSerialize > JsSerialize for BTreeMap< K, V > {
754    #[doc(hidden)]
755    #[inline]
756    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
757        object_into_js( self.iter() )
758    }
759}
760
761__js_serializable_boilerplate!( impl< K, V > for BTreeMap< K, V > where K: AsRef< str >, V: JsSerialize );
762
763impl< K: AsRef< str > + Eq + Hash, V: JsSerialize > JsSerialize for HashMap< K, V > {
764    #[doc(hidden)]
765    #[inline]
766    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
767        object_into_js( self.iter() )
768    }
769}
770
771__js_serializable_boilerplate!( impl< K, V > for HashMap< K, V > where K: AsRef< str > + Eq + Hash, V: JsSerialize );
772
773impl JsSerialize for Value {
774    #[doc(hidden)]
775    fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
776        match *self {
777            Value::Undefined => SerializedUntaggedUndefined.into(),
778            Value::Null => SerializedUntaggedNull.into(),
779            Value::Bool( ref value ) => value._into_js(),
780            Value::Number( ref value ) => value._into_js(),
781            Value::Symbol( ref value ) => value._into_js(),
782            Value::String( ref value ) => value._into_js(),
783            Value::Reference( ref value ) => value._into_js()
784        }
785    }
786}
787
788__js_serializable_boilerplate!( Value );
789
790macro_rules! impl_for_unsafe_typed_array {
791    ($ty:ty, $kind:expr) => {
792        impl< 'r > JsSerialize for UnsafeTypedArray< 'r, $ty > {
793            #[doc(hidden)]
794            #[inline]
795            fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a > {
796                SerializedUntaggedUnsafeTypedArray {
797                    pointer: self.0.as_ptr() as u32 / mem::size_of::< $ty >() as u32,
798                    length: self.0.len() as u32,
799                    kind: $kind
800                }.into()
801            }
802        }
803
804        __js_serializable_boilerplate!( impl< 'a > for UnsafeTypedArray< 'a, $ty > );
805    }
806}
807
808impl_for_unsafe_typed_array!( u8, 0 );
809impl_for_unsafe_typed_array!( i8, 1 );
810impl_for_unsafe_typed_array!( u16, 2 );
811impl_for_unsafe_typed_array!( i16, 3 );
812impl_for_unsafe_typed_array!( u32, 4 );
813impl_for_unsafe_typed_array!( i32, 5 );
814impl_for_unsafe_typed_array!( f32, 6 );
815impl_for_unsafe_typed_array!( f64, 7 );
816
817#[derive(Debug)]
818pub struct FunctionTag;
819
820#[derive(Debug)]
821pub struct NonFunctionTag;
822
823impl< T: JsSerialize > JsSerializeOwned for Newtype< (NonFunctionTag, ()), T > {
824    #[inline]
825    fn into_js_owned< 'x >( value: &'x mut Option< Self > ) -> SerializedValue< 'x > {
826        JsSerialize::_into_js( value.as_ref().unwrap().as_ref() )
827    }
828}
829
830trait FuncallAdapter< F > {
831    extern fn funcall_adapter( callback: *mut F, raw_arguments: *mut SerializedUntaggedArray );
832    extern fn deallocator( callback: *mut F );
833}
834
835macro_rules! impl_for_fn_and_modifier {
836    (
837        args: ($($kind:ident),*),
838        trait: $trait:ident,
839        wrapped type: $wrappedtype:ty,
840        unwrap: $wrapped:ident => $unwrap:expr,
841        serialized to: $serialized_to:tt,
842        call: $callback:ident => $call:expr
843    ) => {
844        impl< $($kind: TryFrom< Value >,)* F > FuncallAdapter< F > for Newtype< (FunctionTag, ($($kind,)*)), $wrappedtype >
845            where F: $trait< ($($kind,)*) > + 'static, F::Output: JsSerializeOwned
846        {
847            #[allow(unused_mut, unused_variables, non_snake_case)]
848            extern fn funcall_adapter(
849                    $callback: *mut F,
850                    raw_arguments: *mut SerializedUntaggedArray
851                )
852            {
853                let mut arguments = unsafe { &*raw_arguments }.deserialize();
854
855                unsafe {
856                    ffi::dealloc( raw_arguments as *mut u8, mem::size_of::< SerializedValue >() );
857                }
858
859                if arguments.len() != F::expected_argument_count() {
860                    // TODO: Should probably throw an exception into the JS world or something like that.
861                    panic!( "Expected {} arguments, got {}", F::expected_argument_count(), arguments.len() );
862                }
863
864                let mut arguments = arguments.drain( .. );
865                let mut nth_argument = 0;
866                $(
867                    let $kind = match arguments.next().unwrap().try_into() {
868                        Ok( value ) => value,
869                        Err( _ ) => {
870                            panic!(
871                                "Argument #{} is not convertible to '{}'",
872                                nth_argument + 1,
873                                type_name::< $kind >()
874                            );
875                        }
876                    };
877
878                    nth_argument += 1;
879                )*
880
881                $crate::private::noop( &mut nth_argument );
882
883                let result = $call;
884
885                let mut result = Some( result );
886                let result = JsSerializeOwned::into_js_owned( &mut result );
887                let result = &result as *const _;
888
889                // This is kinda hacky but I'm not sure how else to do it at the moment.
890                __js_raw_asm!( "Module.STDWEB_PRIVATE.tmp = Module.STDWEB_PRIVATE.to_js( $0 );", result );
891            }
892
893            extern fn deallocator( callback: *mut F ) {
894                let callback = unsafe {
895                    Box::from_raw( callback )
896                };
897
898                drop( callback );
899            }
900        }
901
902        impl< $($kind: TryFrom< Value >,)* F > JsSerializeOwned for Newtype< (FunctionTag, ($($kind,)*)), $wrappedtype >
903            where F: $trait< ($($kind,)*) > + 'static, F::Output: JsSerializeOwned
904        {
905            #[inline]
906            fn into_js_owned< 'a >( value: &'a mut Option< Self > ) -> SerializedValue< 'a > {
907                let $wrapped = value.take().unwrap().unwrap_newtype();
908                let callback: *mut F = Box::into_raw( Box::new( $unwrap ) );
909                let adapter_pointer = <Self as FuncallAdapter< F > >::funcall_adapter;
910                let deallocator_pointer = <Self as FuncallAdapter< F > >::deallocator;
911                $serialized_to {
912                    adapter_pointer: adapter_pointer as u32,
913                    pointer: callback as u32,
914                    deallocator_pointer: deallocator_pointer as u32
915                }.into()
916            }
917        }
918
919        impl< $($kind: TryFrom< Value >,)* F > JsSerializeOwned for Newtype< (FunctionTag, ($($kind,)*)), Option< $wrappedtype > >
920            where F: $trait< ($($kind,)*) > + 'static, F::Output: JsSerializeOwned
921        {
922            #[inline]
923            fn into_js_owned< 'a >( value: &'a mut Option< Self > ) -> SerializedValue< 'a > {
924                if let Some( $wrapped ) = value.take().unwrap().unwrap_newtype() {
925                    let callback: *mut F = Box::into_raw( Box::new( $unwrap ) );
926                    let adapter_pointer = <Newtype< (FunctionTag, ($($kind,)*)), $wrappedtype > as FuncallAdapter< F > >::funcall_adapter;
927                    let deallocator_pointer = <Newtype< (FunctionTag, ($($kind,)*)), $wrappedtype > as FuncallAdapter< F > >::deallocator;
928                    $serialized_to {
929                        adapter_pointer: adapter_pointer as u32,
930                        pointer: callback as u32,
931                        deallocator_pointer: deallocator_pointer as u32
932                    }.into()
933                } else {
934                    SerializedUntaggedNull.into()
935                }
936            }
937        }
938    }
939}
940
941macro_rules! impl_for_fn {
942    ($next:tt => $($kind:ident),*) => {
943        impl_for_fn_and_modifier!(
944            args: ($($kind),*),
945            trait: CallMut,
946            wrapped type: F,
947            unwrap: f => f,
948            serialized to: SerializedUntaggedFunction,
949            call: f => { unsafe { &mut *f }.call_mut( ($($kind,)*) ) }
950        );
951
952        impl_for_fn_and_modifier!(
953            args: ($($kind),*),
954            trait: CallMut,
955            wrapped type: Mut<F>,
956            unwrap: f => {f.0},
957            serialized to: SerializedUntaggedFunctionMut,
958            call: f => { unsafe { &mut *f }.call_mut( ($($kind,)*) ) }
959        );
960
961        impl_for_fn_and_modifier!(
962            args: ($($kind),*),
963            trait: CallOnce,
964            wrapped type: Once<F>,
965            unwrap: f => {f.0},
966            serialized to: SerializedUntaggedFunctionOnce,
967            call: f => { unsafe { Box::from_raw( f ) }.call_once( ($($kind,)*) ) }
968        );
969
970        next! { $next }
971    }
972}
973
974loop_through_identifiers!( impl_for_fn );
975
976impl< 'a, T: ?Sized + JsSerialize > JsSerialize for &'a T {
977    #[doc(hidden)]
978    #[inline]
979    fn _into_js< 'x >( &'x self ) -> SerializedValue< 'x > {
980        T::_into_js( *self )
981    }
982}
983
984impl JsSerialize for ConversionError {
985    #[doc(hidden)]
986    fn _into_js< 'x >( &'x self ) -> SerializedValue< 'x > {
987        let type_error: TypeError = self.into();
988        let reference: Reference = type_error.into();
989        let value: Value = reference.into();
990        global_arena::serialize_value( value )
991    }
992}
993
994#[cfg(test)]
995mod test_deserialization {
996    use std::rc::Rc;
997    use std::cell::{Cell, RefCell};
998    use super::*;
999
1000    #[test]
1001    fn i32() {
1002        assert_eq!( js! { return 100; }, Value::Number( 100_i32.into() ) );
1003    }
1004
1005    #[test]
1006    fn f64() {
1007        assert_eq!( js! { return 100.5; }, Value::Number( 100.5_f64.into() ) );
1008    }
1009
1010    #[test]
1011    fn bool_true() {
1012        assert_eq!( js! { return true; }, Value::Bool( true ) );
1013    }
1014
1015    #[test]
1016    fn bool_false() {
1017        assert_eq!( js! { return false; }, Value::Bool( false ) );
1018    }
1019
1020    #[test]
1021    fn undefined() {
1022        assert_eq!( js! { return undefined; }, Value::Undefined );
1023    }
1024
1025    #[test]
1026    fn null() {
1027        assert_eq!( js! { return null; }, Value::Null );
1028    }
1029
1030    #[test]
1031    fn string() {
1032        assert_eq!( js! { return "Dog"; }, Value::String( "Dog".to_string() ) );
1033    }
1034
1035    #[test]
1036    fn empty_string() {
1037        assert_eq!( js! { return ""; }, Value::String( "".to_string() ) );
1038    }
1039
1040    #[test]
1041    fn symbol() {
1042        let value = js! { return Symbol(); };
1043        assert!( value.is_symbol() );
1044    }
1045
1046    #[test]
1047    fn array() {
1048        assert_eq!( js! { return [1, 2]; }.is_array(), true );
1049    }
1050
1051    #[test]
1052    fn object() {
1053        assert_eq!( js! { return {"one": 1, "two": 2}; }.is_object(), true );
1054    }
1055
1056    #[test]
1057    fn object_into_btreemap() {
1058        let object = js! { return {"one": 1, "two": 2}; }.into_object().unwrap();
1059        let object: BTreeMap< String, Value > = object.into();
1060        assert_eq!( object, [
1061            ("one".to_string(), Value::Number(1.into())),
1062            ("two".to_string(), Value::Number(2.into()))
1063        ].iter().cloned().collect() );
1064    }
1065
1066    #[test]
1067    fn object_into_hashmap() {
1068        let object = js! { return {"one": 1, "two": 2}; }.into_object().unwrap();
1069        let object: HashMap< String, Value > = object.into();
1070        assert_eq!( object, [
1071            ("one".to_string(), Value::Number(1.into())),
1072            ("two".to_string(), Value::Number(2.into()))
1073        ].iter().cloned().collect() );
1074    }
1075
1076    #[test]
1077    fn array_into_vector() {
1078        let array = js! { return ["one", 1]; }.into_array().unwrap();
1079        let array: Vec< Value > = array.into();
1080        assert_eq!( array, &[
1081            Value::String( "one".to_string() ),
1082            Value::Number( 1.into() )
1083        ]);
1084    }
1085
1086    #[test]
1087    fn reference() {
1088        assert_eq!( js! { return new Date(); }.is_reference(), true );
1089    }
1090
1091    #[test]
1092    fn bad_reference() {
1093        assert_eq!( js! {
1094            var WeakMapProto = WeakMap.prototype;
1095            if (WeakMapProto.BAD_REFERENCE === undefined) {
1096                WeakMapProto.BAD_REFERENCE = {};
1097                WeakMapProto.oldSet = WeakMapProto.set;
1098                WeakMapProto.set = function(key, value) {
1099                    if (key === WeakMapProto.BAD_REFERENCE) {
1100                        throw new TypeError("BAD_REFERENCE");
1101                    } else {
1102                        return this.oldSet(key, value);
1103                    }
1104                };
1105            }
1106            return WeakMapProto.BAD_REFERENCE;
1107        }.is_reference(), true );
1108    }
1109
1110    #[test]
1111    fn arguments() {
1112        let value = js! {
1113            return (function() {
1114                return arguments;
1115            })( 1, 2 );
1116        };
1117
1118        assert_eq!( value.is_array(), false );
1119    }
1120
1121    #[test]
1122    fn function() {
1123        let value = Rc::new( Cell::new( 0 ) );
1124        let fn_value = value.clone();
1125
1126        js! {
1127            var callback = @{move || { fn_value.set( 1 ); }};
1128            callback();
1129            callback.drop();
1130        };
1131
1132        assert_eq!( value.get(), 1 );
1133    }
1134
1135    #[test]
1136    fn function_returning_bool() {
1137        let result = js! {
1138            var callback = @{move || { return true }};
1139            var result = callback();
1140            callback.drop();
1141
1142            return result;
1143        };
1144
1145        assert_eq!( result, Value::Bool( true ) );
1146    }
1147
1148    #[test]
1149    fn function_with_single_bool_argument() {
1150        let value = Rc::new( Cell::new( false ) );
1151        let fn_value = value.clone();
1152
1153        js! {
1154            var callback = @{move |value: bool| { fn_value.set( value ); }};
1155            callback( true );
1156            callback.drop();
1157        };
1158
1159        assert_eq!( value.get(), true );
1160    }
1161
1162    #[test]
1163    fn function_inside_an_option() {
1164        let value = Rc::new( Cell::new( 0 ) );
1165        let fn_value = value.clone();
1166
1167        js! {
1168            var callback = @{Some( move || { fn_value.set( 1 ); } )};
1169            callback();
1170            callback.drop();
1171        };
1172
1173        assert_eq!( value.get(), 1 );
1174    }
1175
1176    #[test]
1177    #[allow(unused_assignments)]
1178    fn function_inside_an_empty_option() {
1179        let mut callback = Some( move || () );
1180        callback = None;
1181
1182        let result = js! {
1183            var callback = @{callback};
1184            return callback === null;
1185        };
1186
1187        assert_eq!( result, Value::Bool( true ) );
1188    }
1189
1190    #[test]
1191    fn function_once() {
1192        fn call< F: FnOnce( String ) -> String + 'static >( callback: F ) -> Value {
1193            js!(
1194                var callback = @{Once( callback )};
1195                return callback( "Dog" );
1196            )
1197        }
1198
1199        let suffix = "!".to_owned();
1200        let result = call( move |value| { return value + suffix.as_str() } );
1201        assert_eq!( result, Value::String( "Dog!".to_owned() ) );
1202    }
1203
1204    #[test]
1205    fn function_mut() {
1206        let mut count = 0;
1207        let callback = move || -> i32 {
1208            count += 1;
1209            count
1210        };
1211        let callback = js! { return @{Mut(callback)}; };
1212        assert_eq!({ let x : i32 = js!{ return @{&callback}(); }.try_into().unwrap(); x }, 1);
1213        assert_eq!({ let x : i32 = js!{ return @{&callback}(); }.try_into().unwrap(); x }, 2);
1214        assert_eq!({ let x : i32 = js!{ return @{&callback}(); }.try_into().unwrap(); x }, 3);
1215        js!{ @{callback}.drop(); };
1216    }
1217
1218    #[test]
1219    fn function_once_cannot_be_called_twice() {
1220        fn call< F: FnOnce() + 'static >( callback: F ) -> Value {
1221            js!(
1222                var callback = @{Once( callback )};
1223                callback();
1224
1225                try {
1226                    callback();
1227                } catch( error ) {
1228                    if( error instanceof ReferenceError ) {
1229                        return true;
1230                    }
1231                }
1232
1233                return false;
1234            )
1235        }
1236
1237        let result = call( move || {} );
1238        assert_eq!( result, Value::Bool( true ) );
1239    }
1240
1241    #[test]
1242    fn function_once_cannot_be_called_after_being_dropped() {
1243        fn call< F: FnOnce() + 'static >( callback: F ) -> Value {
1244            js!(
1245                var callback = @{Once( callback )};
1246                callback.drop();
1247
1248                try {
1249                    callback();
1250                } catch( error ) {
1251                    if( error instanceof ReferenceError ) {
1252                        return true;
1253                    }
1254                }
1255
1256                return false;
1257            )
1258        }
1259
1260        let result = call( move || {} );
1261        assert_eq!( result, Value::Bool( true ) );
1262    }
1263
1264    #[test]
1265    fn function_once_calling_drop_after_being_called_does_not_do_anything() {
1266        fn call< F: FnOnce() + 'static >( callback: F ) -> Value {
1267            js!(
1268                var callback = @{Once( callback )};
1269                callback();
1270                callback.drop();
1271
1272                return true;
1273            )
1274        }
1275
1276        let result = call( move || {} );
1277        assert_eq!( result, Value::Bool( true ) );
1278    }
1279
1280    #[test]
1281    fn function_once_calling_drop_twice_does_not_do_anything() {
1282        fn call< F: FnOnce() + 'static >( callback: F ) -> Value {
1283            js!(
1284                var callback = @{Once( callback )};
1285                callback.drop();
1286                callback.drop();
1287
1288                return true;
1289            )
1290        }
1291
1292        let result = call( move || {} );
1293        assert_eq!( result, Value::Bool( true ) );
1294    }
1295
1296    #[test]
1297    fn issue_273() {
1298        let mut count = 0;
1299        let f = move |callback: ::stdweb::Value| {
1300            count += 1;
1301            js! {
1302                @{callback}();
1303            };
1304        };
1305
1306        let result = js! {
1307            let f = @{Mut(f)};
1308
1309            let caught = false;
1310
1311            try {
1312                f(function () {
1313                    f(function() {});
1314                });
1315            } catch ( error ) {
1316                if( error instanceof ReferenceError ) {
1317                    caught = true;
1318                }
1319            }
1320
1321            f.drop();
1322
1323            return caught;
1324        };
1325        assert_eq!( result, Value::Bool( true ) );
1326    }
1327
1328    #[test]
1329    fn issue_277() {
1330        struct MyStruct {
1331            was_dropped: bool
1332        }
1333        impl MyStruct {
1334            fn consume(self) {}
1335        }
1336        impl Drop for MyStruct {
1337            fn drop(&mut self) {
1338                assert_eq!(self.was_dropped, false);
1339                self.was_dropped = true;
1340            }
1341        }
1342
1343        let s = MyStruct { was_dropped: false };
1344
1345        let f = move || -> () {
1346            s.consume();
1347            unreachable!(); // never actually called
1348        };
1349
1350        js! {
1351            let f = @{Once(f)};
1352
1353            let drop = f.drop;
1354            drop();
1355            drop();
1356        };
1357    }
1358
1359    #[test]
1360    fn test_closure_dropped_while_being_called_is_dropped_after_it_returns() {
1361        struct MarkTrueOnDrop( Rc< Cell< bool > > );
1362        impl Drop for MarkTrueOnDrop {
1363            fn drop( &mut self ) {
1364                self.0.set( true );
1365            }
1366        }
1367
1368        let was_dropped = Rc::new( Cell::new( false ) );
1369        let was_dropped_clone = was_dropped.clone();
1370        let callback = move |itself: Value, check_if_dropped: Value| {
1371            let _mark_true_on_drop = MarkTrueOnDrop( was_dropped_clone.clone() );
1372            js!(
1373                @{itself}.drop();
1374                @{check_if_dropped}();
1375            );
1376        };
1377
1378        let check_if_dropped = move || {
1379            assert_eq!( was_dropped.get(), false );
1380        };
1381
1382        js!(
1383            var callback = @{callback};
1384            callback( callback, @{Once( check_if_dropped )} );
1385        );
1386    }
1387
1388    #[test]
1389    fn test_dropping_the_closure_while_it_is_being_called_will_make_future_calls_throw() {
1390        #[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
1391        #[reference(instance_of = "ReferenceError")]
1392        pub struct ReferenceError( Reference );
1393
1394        let counter = Rc::new( Cell::new( 0 ) );
1395        let counter_clone = counter.clone();
1396        let caught_value = Rc::new( RefCell::new( Value::Null ) );
1397        let caught_value_clone = caught_value.clone();
1398        let callback = move |itself: Value| {
1399            let value = counter_clone.get();
1400            counter_clone.set( value + 1 );
1401
1402            if value == 0 {
1403                let caught = js!(
1404                    var callback = @{itself};
1405                    callback.drop();
1406
1407                    var caught = null;
1408                    try {
1409                        callback( callback );
1410                    } catch( error ) {
1411                        caught = error;
1412                    }
1413
1414                    return caught;
1415                );
1416                *caught_value_clone.borrow_mut() = caught;
1417            }
1418        };
1419
1420        js!(
1421            var callback = @{callback};
1422            callback( callback );
1423        );
1424
1425        assert_eq!( counter.get(), 1 );
1426        let reference_error: Result< ReferenceError, _ > = caught_value.borrow().clone().try_into();
1427        assert!( reference_error.is_ok() );
1428    }
1429
1430    #[test]
1431    fn no_return() {
1432        let values = Rc::new( RefCell::new( Vec::new() ) );
1433        let values_clone = values.clone();
1434        let callback = move |value: i32| {
1435            values_clone.borrow_mut().push( value );
1436        };
1437
1438        let _: () = js!( @(no_return)
1439            var cb = @{Mut( callback.clone() )};
1440            cb( 1 );
1441            cb.drop();
1442        );
1443
1444        let _: () = js!( @(no_return)
1445            var cb = @{Mut( callback.clone() )};
1446            cb( 2 );
1447            cb.drop();
1448            return 20;
1449        );
1450
1451        let a: Value = js!(
1452            var cb = @{Mut( callback.clone() )};
1453            cb( 3 );
1454            cb.drop();
1455        );
1456
1457        let b: Value = js!(
1458            var cb = @{Mut( callback )};
1459            cb( 4 );
1460            cb.drop();
1461            return 40;
1462        );
1463
1464        assert_eq!( *values.borrow(), &[1, 2, 3, 4] );
1465        assert_eq!( a, Value::Undefined );
1466        assert_eq!( b, 40 )
1467    }
1468}
1469
1470#[cfg(test)]
1471mod test_serialization {
1472    use super::*;
1473    use std::borrow::Cow;
1474
1475    #[test]
1476    fn object_from_btreemap() {
1477        let object: BTreeMap< _, _ > = [
1478            ("number".to_string(), Value::Number( 123.into() )),
1479            ("string".to_string(), Value::String( "Hello!".into() ))
1480        ].iter().cloned().collect();
1481
1482        let result = js! {
1483            var object = @{object};
1484            return object.number === 123 && object.string === "Hello!" && Object.keys( object ).length === 2;
1485        };
1486        assert_eq!( result, Value::Bool( true ) );
1487    }
1488
1489    #[test]
1490    fn object_from_borrowed_btreemap() {
1491        let object: BTreeMap< _, _ > = [
1492            ("number".to_string(), Value::Number( 123.into() ))
1493        ].iter().cloned().collect();
1494
1495        let result = js! {
1496            var object = @{&object};
1497            return object.number === 123 && Object.keys( object ).length === 1;
1498        };
1499        assert_eq!( result, Value::Bool( true ) );
1500    }
1501
1502    #[test]
1503    fn object_from_btreemap_with_convertible_key_and_value() {
1504        let key: Cow< str > = "number".into();
1505        let object: BTreeMap< _, _ > = [
1506            (key, 123)
1507        ].iter().cloned().collect();
1508
1509        let result = js! {
1510            var object = @{object};
1511            return object.number === 123 && Object.keys( object ).length === 1;
1512        };
1513        assert_eq!( result, Value::Bool( true ) );
1514    }
1515
1516    #[test]
1517    fn object_from_hashmap() {
1518        let object: HashMap< _, _ > = [
1519            ("number".to_string(), Value::Number( 123.into() )),
1520            ("string".to_string(), Value::String( "Hello!".into() ))
1521        ].iter().cloned().collect();
1522
1523        let result = js! {
1524            var object = @{object};
1525            return object.number === 123 && object.string === "Hello!" && Object.keys( object ).length === 2;
1526        };
1527        assert_eq!( result, Value::Bool( true ) );
1528    }
1529
1530    #[test]
1531    fn vector_of_strings() {
1532        let vec: Vec< _ > = vec![
1533            "one".to_string(),
1534            "two".to_string()
1535        ];
1536
1537        let result = js! {
1538            var vec = @{vec};
1539            return vec[0] === "one" && vec[1] === "two" && vec.length === 2;
1540        };
1541        assert_eq!( result, Value::Bool( true ) );
1542    }
1543
1544    #[test]
1545    fn multiple() {
1546        let reference: Reference = js! {
1547            return new Date();
1548        }.try_into().unwrap();
1549
1550        let result = js! {
1551            var callback = @{|| {}};
1552            var reference = @{&reference};
1553            var string = @{"Hello!"};
1554            return Object.prototype.toString.call( callback ) === "[object Function]" &&
1555                Object.prototype.toString.call( reference ) === "[object Date]" &&
1556                Object.prototype.toString.call( string ) === "[object String]"
1557        };
1558        assert_eq!( result, Value::Bool( true ) );
1559    }
1560
1561    #[test]
1562    fn serialize_0() {
1563        assert_eq!(
1564            js! { return 0; },
1565            0
1566        );
1567    }
1568
1569    #[test]
1570    fn serialize_1() {
1571        assert_eq!(
1572            js! { return @{1}; },
1573            1
1574        );
1575    }
1576
1577    #[test]
1578    fn serialize_2() {
1579        assert_eq!(
1580            js! { return @{1} + @{2}; },
1581            1 + 2
1582        );
1583    }
1584
1585    #[test]
1586    fn serialize_3() {
1587        assert_eq!(
1588            js! { return @{1} + @{2} + @{3}; },
1589            1 + 2 + 3
1590        );
1591    }
1592
1593    #[test]
1594    fn serialize_4() {
1595        assert_eq!(
1596            js! { return @{1} + @{2} + @{3} + @{4}; },
1597            1 + 2 + 3 + 4
1598        );
1599    }
1600
1601    #[test]
1602    fn serialize_5() {
1603        assert_eq!(
1604            js! { return @{1} + @{2} + @{3} + @{4} + @{5}; },
1605            1 + 2 + 3 + 4 + 5
1606        );
1607    }
1608
1609    #[test]
1610    fn serialize_6() {
1611        assert_eq!(
1612            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6}; },
1613            1 + 2 + 3 + 4 + 5 + 6
1614        );
1615    }
1616
1617    #[test]
1618    fn serialize_7() {
1619        assert_eq!(
1620            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7}; },
1621            1 + 2 + 3 + 4 + 5 + 6 + 7
1622        );
1623    }
1624
1625    #[test]
1626    fn serialize_8() {
1627        assert_eq!(
1628            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8}; },
1629            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8
1630        );
1631    }
1632
1633    #[test]
1634    fn serialize_9() {
1635        assert_eq!(
1636            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9}; },
1637            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9
1638        );
1639    }
1640
1641    #[test]
1642    fn serialize_10() {
1643        assert_eq!(
1644            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10}; },
1645            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10
1646        );
1647    }
1648
1649    #[test]
1650    fn serialize_11() {
1651        assert_eq!(
1652            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11}; },
1653            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11
1654        );
1655    }
1656
1657    #[test]
1658    fn serialize_12() {
1659        assert_eq!(
1660            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11} + @{12}; },
1661            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12
1662        );
1663    }
1664
1665    #[test]
1666    fn serialize_13() {
1667        assert_eq!(
1668            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11} + @{12} + @{13}; },
1669            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13
1670        );
1671    }
1672
1673    #[test]
1674    fn serialize_14() {
1675        assert_eq!(
1676            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11} + @{12} + @{13} + @{14}; },
1677            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14
1678        );
1679    }
1680
1681    #[test]
1682    fn serialize_15() {
1683        assert_eq!(
1684            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11} + @{12} + @{13} + @{14} + @{15}; },
1685            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15
1686        );
1687    }
1688
1689    #[test]
1690    fn serialize_16() {
1691        assert_eq!(
1692            js! { return @{1} + @{2} + @{3} + @{4} + @{5} + @{6} + @{7} + @{8} + @{9} + @{10} + @{11} + @{12} + @{13} + @{14} + @{15} + @{16}; },
1693            1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 + 13 + 14 + 15 + 16
1694        );
1695    }
1696
1697    #[test]
1698    fn interpolated_args_are_converted_at_the_start() {
1699        let mut string = "1".to_owned();
1700        let callback = js! {
1701            return function() {
1702                return @{&string};
1703            }
1704        };
1705
1706        unsafe {
1707            string.as_bytes_mut()[0] = b'2';
1708        }
1709
1710        let result = js! {
1711            return @{callback}();
1712        };
1713
1714        assert_eq!( result, "1" );
1715    }
1716
1717    macro_rules! test_unsafe_typed_array {
1718        ($test_name:ident, $ty:ty, $js_type_name:ident) => {
1719            #[allow(trivial_numeric_casts)]
1720            #[test]
1721            fn $test_name() {
1722                let slice: &[$ty] = &[1 as $ty, 2 as $ty, 3 as $ty];
1723                let slice = unsafe { UnsafeTypedArray::new( slice ) };
1724                let result: Vec< Value > = js!(
1725                    var slice = @{slice};
1726                    var sum = slice[0] + slice[1] + slice[2];
1727                    var name = slice.constructor.name;
1728                    var length = slice.length;
1729                    return [name, sum, length]
1730                ).try_into().unwrap();
1731
1732                let mut result = result.into_iter();
1733                let name: String = result.next().unwrap().try_into().unwrap();
1734                let sum: f64 = result.next().unwrap().try_into().unwrap();
1735                let length: usize = result.next().unwrap().try_into().unwrap();
1736
1737                assert_eq!( name, stringify!( $js_type_name ) );
1738                assert_eq!( sum as u64, 6 );
1739                assert_eq!( length, 3 );
1740            }
1741        }
1742    }
1743
1744    test_unsafe_typed_array!( test_unsafe_typed_array_u8, u8, Uint8Array );
1745    test_unsafe_typed_array!( test_unsafe_typed_array_i8, i8, Int8Array );
1746    test_unsafe_typed_array!( test_unsafe_typed_array_u16, u16, Uint16Array );
1747    test_unsafe_typed_array!( test_unsafe_typed_array_i16, i16, Int16Array );
1748    test_unsafe_typed_array!( test_unsafe_typed_array_u32, u32, Uint32Array );
1749    test_unsafe_typed_array!( test_unsafe_typed_array_i32, i32, Int32Array );
1750    test_unsafe_typed_array!( test_unsafe_typed_array_f32, f32, Float32Array );
1751    test_unsafe_typed_array!( test_unsafe_typed_array_f64, f64, Float64Array );
1752}
1753
1754// TODO: Move this back inside the test module.
1755//
1756// This had to be temporarily moved here due to a bug in Rust
1757// where the following error is generated if it's defined under
1758// the module:
1759//
1760//    error: cannot determine resolution for the attribute macro `reference`
1761//
1762#[cfg(test)]
1763#[derive(Clone, Debug, PartialEq, Eq, ReferenceType)]
1764#[reference(instance_of = "Error")]
1765pub struct TestError( Reference );
1766
1767#[cfg(test)]
1768mod test_reserialization {
1769    use super::*;
1770    use webcore::array::Array;
1771
1772    #[test]
1773    fn i32() {
1774        assert_eq!( js! { return @{100}; }, Value::Number( 100_i32.into() ) );
1775    }
1776
1777    #[test]
1778    fn f64() {
1779        assert_eq!( js! { return @{100.5}; }, Value::Number( 100.5_f64.into() ) );
1780    }
1781
1782    #[test]
1783    fn bool_true() {
1784        assert_eq!( js! { return @{true}; }, Value::Bool( true ) );
1785    }
1786
1787    #[test]
1788    fn bool_false() {
1789        assert_eq!( js! { return @{false}; }, Value::Bool( false ) );
1790    }
1791
1792    #[test]
1793    fn undefined() {
1794        assert_eq!( js! { return @{Undefined}; }, Value::Undefined );
1795    }
1796
1797    #[test]
1798    fn null() {
1799        assert_eq!( js! { return @{Null}; }, Value::Null );
1800    }
1801
1802    #[test]
1803    fn string() {
1804        assert_eq!( js! { return @{"Dog"}; }, Value::String( "Dog".to_string() ) );
1805    }
1806
1807    #[test]
1808    fn empty_string() {
1809        assert_eq!( js! { return @{""}; }, Value::String( "".to_string() ) );
1810    }
1811
1812    #[test]
1813    fn string_with_non_bmp_character() {
1814        assert_eq!( js! { return @{"๐Ÿ˜"} + ", ๐Ÿ˜"; }, Value::String( "๐Ÿ˜, ๐Ÿ˜".to_string() ) );
1815    }
1816
1817    #[test]
1818    fn array() {
1819        let array: Array = vec![ Value::Number( 1.into() ), Value::Number( 2.into() ) ].into();
1820        assert_eq!( js! { return @{&array}; }.into_reference().unwrap(), *array.as_ref() );
1821    }
1822
1823    #[test]
1824    fn array_values_are_not_compared_by_value() {
1825        let array: Array = vec![ Value::Number( 1.into() ), Value::Number( 2.into() ) ].into();
1826        assert_ne!( js! { return @{&[1, 2][..]}; }.into_reference().unwrap(), *array.as_ref() );
1827    }
1828
1829    #[test]
1830    fn object() {
1831        let object: BTreeMap< _, _ > = [
1832            ("one".to_string(), Value::Number( 1.into() )),
1833            ("two".to_string(), Value::Number( 2.into() ))
1834        ].iter().cloned().collect();
1835
1836        let object: Value = object.into();
1837        assert_eq!( js! { return @{&object} }, object );
1838    }
1839
1840    #[test]
1841    fn symbol() {
1842        let value_1: Symbol = js! { return Symbol(); }.try_into().unwrap();
1843        let value_2: Symbol = js! { return @{&value_1}; }.try_into().unwrap();
1844        assert_eq!( value_1, value_2 );
1845        assert_eq!( js! { return @{value_1} === @{value_2}; }, true );
1846    }
1847
1848    #[test]
1849    fn cloned_symbol() {
1850        let value_1: Symbol = js! { return Symbol(); }.try_into().unwrap();
1851        let value_2 = value_1.clone();
1852        assert_eq!( value_1, value_2 );
1853        assert_eq!( js! { return @{value_1} === @{value_2}; }, true );
1854    }
1855
1856    #[test]
1857    fn different_symbols() {
1858        let value_1: Symbol = js! { return Symbol(); }.try_into().unwrap();
1859        let value_2: Symbol = js! { return Symbol(); }.try_into().unwrap();
1860        assert_ne!( value_1, value_2 );
1861        assert_eq!( js! { return @{value_1} !== @{value_2}; }, true );
1862    }
1863
1864    #[test]
1865    fn reference() {
1866        let date = js! { return new Date(); };
1867        assert_eq!( js! { return Object.prototype.toString.call( @{date} ) }, "[object Date]" );
1868    }
1869
1870    #[test]
1871    fn reference_by_ref() {
1872        let date = js! { return new Date(); };
1873        assert_eq!( js! { return Object.prototype.toString.call( @{&date} ) }, "[object Date]" );
1874    }
1875
1876    #[test]
1877    fn option_some() {
1878        assert_eq!( js! { return @{Some( true )}; }, Value::Bool( true ) );
1879    }
1880
1881    #[test]
1882    fn option_none() {
1883        let boolean_none: Option< bool > = None;
1884        assert_eq!( js! { return @{boolean_none}; }, Value::Null );
1885    }
1886
1887    #[test]
1888    fn optional_arg_some() {
1889        assert_eq!( js! { return @{OptionalArg::Some( true )}; }, Value::Bool( true ) );
1890    }
1891
1892    #[test]
1893    fn optional_arg_none() {
1894        let boolean_none: OptionalArg< bool > = OptionalArg::None;
1895        assert_eq!( js! { return @{boolean_none}; }, Value::Undefined );
1896    }
1897
1898    #[test]
1899    fn value() {
1900        assert_eq!( js! { return @{Value::String( "Dog".to_string() )}; }, Value::String( "Dog".to_string() ) );
1901    }
1902
1903    #[test]
1904    fn closure_context() {
1905        let constant: u32 = 0x12345678;
1906        let callback = move || {
1907            let value: Value = constant.into();
1908            value
1909        };
1910
1911        let value = js! {
1912            return @{callback}();
1913        };
1914
1915        assert_eq!( value, Value::Number( 0x12345678_i32.into() ) );
1916    }
1917
1918    #[test]
1919    fn string_identity_function() {
1920        fn identity( string: String ) -> String {
1921            string
1922        }
1923
1924        let empty = js! {
1925            var identity = @{identity};
1926            return identity( "" );
1927        };
1928
1929        assert_eq!( empty, Value::String( "".to_string() ) );
1930
1931        let non_empty = js! {
1932            var identity = @{identity};
1933            return identity( "ๆญป็ฅžใฏใ‚Šใ‚“ใ”ใ—ใ‹้ฃŸในใชใ„!" );
1934        };
1935
1936        assert_eq!( non_empty, Value::String( "ๆญป็ฅžใฏใ‚Šใ‚“ใ”ใ—ใ‹้ฃŸในใชใ„!".to_string() ) );
1937    }
1938
1939    type Error = TestError;
1940
1941    #[test]
1942    fn closure_returning_reference_object() {
1943        fn identity( error: Error ) -> Error {
1944            error
1945        }
1946
1947        let value = js! {
1948            var identity = @{identity};
1949            return identity( new ReferenceError() );
1950        };
1951
1952        assert!( instanceof!( value, Error ) );
1953    }
1954}