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
64pub trait JsSerialize {
69 #[doc(hidden)]
70 fn _into_js< 'a >( &'a self ) -> SerializedValue< 'a >;
71}
72
73#[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
218struct 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 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 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 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 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 __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!(); };
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#[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}