@@ -40,6 +40,7 @@ use jsval::{JSVal, ObjectValue, ObjectOrNullValue, StringValue};
40
40
use rust:: { ToBoolean , ToNumber , ToUint16 , ToInt32 , ToUint32 , ToInt64 , ToUint64 , ToString } ;
41
41
use libc;
42
42
use num_traits:: { Bounded , Zero } ;
43
+ use std:: borrow:: Cow ;
43
44
use std:: rc:: Rc ;
44
45
use std:: { ptr, slice} ;
45
46
@@ -91,6 +92,25 @@ pub trait ToJSValConvertible {
91
92
unsafe fn to_jsval ( & self , cx : * mut JSContext , rval : MutableHandleValue ) ;
92
93
}
93
94
95
+ /// An enum to better support enums through FromJSValConvertible::from_jsval.
96
+ #[ derive( PartialEq , Eq , Clone , Debug ) ]
97
+ pub enum ConversionResult < T > {
98
+ /// Everything went fine.
99
+ Success ( T ) ,
100
+ /// Pending exception.
101
+ Failure ( Cow < ' static , str > ) ,
102
+ }
103
+
104
+ impl < T > ConversionResult < T > {
105
+ /// Returns Some(value) if it is `ConversionResult::Success`.
106
+ pub fn get_success_value ( & self ) -> Option < & T > {
107
+ match * self {
108
+ ConversionResult :: Success ( ref v) => Some ( v) ,
109
+ _ => None ,
110
+ }
111
+ }
112
+ }
113
+
94
114
/// A trait to convert `JSVal`s to Rust types.
95
115
pub trait FromJSValConvertible : Sized {
96
116
/// Optional configurable behaviour switch; use () for no configuration.
@@ -102,7 +122,7 @@ pub trait FromJSValConvertible: Sized {
102
122
unsafe fn from_jsval ( cx : * mut JSContext ,
103
123
val : HandleValue ,
104
124
option : Self :: Config )
105
- -> Result < Self , ( ) > ;
125
+ -> Result < ConversionResult < Self > , ( ) > ;
106
126
}
107
127
108
128
/// Behavior for converting out-of-range integers.
@@ -118,7 +138,7 @@ pub enum ConversionBehavior {
118
138
119
139
/// Try to cast the number to a smaller type, but
120
140
/// if it doesn't fit, it will return an error.
121
- unsafe fn enforce_range < D > ( cx : * mut JSContext , d : f64 ) -> Result < D , ( ) >
141
+ unsafe fn enforce_range < D > ( cx : * mut JSContext , d : f64 ) -> Result < ConversionResult < D > , ( ) >
122
142
where D : Bounded + As < f64 > ,
123
143
f64 : As < D >
124
144
{
@@ -129,7 +149,7 @@ unsafe fn enforce_range<D>(cx: *mut JSContext, d: f64) -> Result<D, ()>
129
149
130
150
let rounded = d. round ( ) ;
131
151
if D :: min_value ( ) . cast ( ) <= rounded && rounded <= D :: max_value ( ) . cast ( ) {
132
- Ok ( rounded. cast ( ) )
152
+ Ok ( ConversionResult :: Success ( rounded. cast ( ) ) )
133
153
} else {
134
154
throw_type_error ( cx, "value out of range in an EnforceRange argument" ) ;
135
155
Err ( ( ) )
@@ -177,8 +197,8 @@ impl FromJSValConvertible for JSVal {
177
197
unsafe fn from_jsval ( _cx : * mut JSContext ,
178
198
value : HandleValue ,
179
199
_option : ( ) )
180
- -> Result < JSVal , ( ) > {
181
- Ok ( value. get ( ) )
200
+ -> Result < ConversionResult < JSVal > , ( ) > {
201
+ Ok ( ConversionResult :: Success ( value. get ( ) ) )
182
202
}
183
203
}
184
204
@@ -196,15 +216,15 @@ impl ToJSValConvertible for HandleValue {
196
216
unsafe fn convert_int_from_jsval < T , M > ( cx : * mut JSContext , value : HandleValue ,
197
217
option : ConversionBehavior ,
198
218
convert_fn : unsafe fn ( * mut JSContext , HandleValue ) -> Result < M , ( ) > )
199
- -> Result < T , ( ) >
219
+ -> Result < ConversionResult < T > , ( ) >
200
220
where T : Bounded + Zero + As < f64 > ,
201
221
M : Zero + As < T > ,
202
222
f64 : As < T >
203
223
{
204
224
match option {
205
- ConversionBehavior :: Default => Ok ( try!( convert_fn ( cx, value) ) . cast ( ) ) ,
225
+ ConversionBehavior :: Default => Ok ( ConversionResult :: Success ( try!( convert_fn ( cx, value) ) . cast ( ) ) ) ,
206
226
ConversionBehavior :: EnforceRange => enforce_range ( cx, try!( ToNumber ( cx, value) ) ) ,
207
- ConversionBehavior :: Clamp => Ok ( clamp_to ( try!( ToNumber ( cx, value) ) ) ) ,
227
+ ConversionBehavior :: Clamp => Ok ( ConversionResult :: Success ( clamp_to ( try!( ToNumber ( cx, value) ) ) ) ) ,
208
228
}
209
229
}
210
230
@@ -219,8 +239,8 @@ impl ToJSValConvertible for bool {
219
239
// https://heycam.github.io/webidl/#es-boolean
220
240
impl FromJSValConvertible for bool {
221
241
type Config = ( ) ;
222
- unsafe fn from_jsval ( _cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < bool , ( ) > {
223
- Ok ( ToBoolean ( val) )
242
+ unsafe fn from_jsval ( _cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < ConversionResult < bool > , ( ) > {
243
+ Ok ( ToBoolean ( val) ) . map ( ConversionResult :: Success )
224
244
}
225
245
}
226
246
@@ -238,7 +258,7 @@ impl FromJSValConvertible for i8 {
238
258
unsafe fn from_jsval ( cx : * mut JSContext ,
239
259
val : HandleValue ,
240
260
option : ConversionBehavior )
241
- -> Result < i8 , ( ) > {
261
+ -> Result < ConversionResult < i8 > , ( ) > {
242
262
convert_int_from_jsval ( cx, val, option, ToInt32 )
243
263
}
244
264
}
@@ -257,7 +277,7 @@ impl FromJSValConvertible for u8 {
257
277
unsafe fn from_jsval ( cx : * mut JSContext ,
258
278
val : HandleValue ,
259
279
option : ConversionBehavior )
260
- -> Result < u8 , ( ) > {
280
+ -> Result < ConversionResult < u8 > , ( ) > {
261
281
convert_int_from_jsval ( cx, val, option, ToInt32 )
262
282
}
263
283
}
@@ -276,7 +296,7 @@ impl FromJSValConvertible for i16 {
276
296
unsafe fn from_jsval ( cx : * mut JSContext ,
277
297
val : HandleValue ,
278
298
option : ConversionBehavior )
279
- -> Result < i16 , ( ) > {
299
+ -> Result < ConversionResult < i16 > , ( ) > {
280
300
convert_int_from_jsval ( cx, val, option, ToInt32 )
281
301
}
282
302
}
@@ -295,7 +315,7 @@ impl FromJSValConvertible for u16 {
295
315
unsafe fn from_jsval ( cx : * mut JSContext ,
296
316
val : HandleValue ,
297
317
option : ConversionBehavior )
298
- -> Result < u16 , ( ) > {
318
+ -> Result < ConversionResult < u16 > , ( ) > {
299
319
convert_int_from_jsval ( cx, val, option, ToUint16 )
300
320
}
301
321
}
@@ -314,7 +334,7 @@ impl FromJSValConvertible for i32 {
314
334
unsafe fn from_jsval ( cx : * mut JSContext ,
315
335
val : HandleValue ,
316
336
option : ConversionBehavior )
317
- -> Result < i32 , ( ) > {
337
+ -> Result < ConversionResult < i32 > , ( ) > {
318
338
convert_int_from_jsval ( cx, val, option, ToInt32 )
319
339
}
320
340
}
@@ -333,7 +353,7 @@ impl FromJSValConvertible for u32 {
333
353
unsafe fn from_jsval ( cx : * mut JSContext ,
334
354
val : HandleValue ,
335
355
option : ConversionBehavior )
336
- -> Result < u32 , ( ) > {
356
+ -> Result < ConversionResult < u32 > , ( ) > {
337
357
convert_int_from_jsval ( cx, val, option, ToUint32 )
338
358
}
339
359
}
@@ -352,7 +372,7 @@ impl FromJSValConvertible for i64 {
352
372
unsafe fn from_jsval ( cx : * mut JSContext ,
353
373
val : HandleValue ,
354
374
option : ConversionBehavior )
355
- -> Result < i64 , ( ) > {
375
+ -> Result < ConversionResult < i64 > , ( ) > {
356
376
convert_int_from_jsval ( cx, val, option, ToInt64 )
357
377
}
358
378
}
@@ -371,7 +391,7 @@ impl FromJSValConvertible for u64 {
371
391
unsafe fn from_jsval ( cx : * mut JSContext ,
372
392
val : HandleValue ,
373
393
option : ConversionBehavior )
374
- -> Result < u64 , ( ) > {
394
+ -> Result < ConversionResult < u64 > , ( ) > {
375
395
convert_int_from_jsval ( cx, val, option, ToUint64 )
376
396
}
377
397
}
@@ -387,9 +407,9 @@ impl ToJSValConvertible for f32 {
387
407
// https://heycam.github.io/webidl/#es-float
388
408
impl FromJSValConvertible for f32 {
389
409
type Config = ( ) ;
390
- unsafe fn from_jsval ( cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < f32 , ( ) > {
410
+ unsafe fn from_jsval ( cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < ConversionResult < f32 > , ( ) > {
391
411
let result = ToNumber ( cx, val) ;
392
- result. map ( |f| f as f32 )
412
+ result. map ( |f| f as f32 ) . map ( ConversionResult :: Success )
393
413
}
394
414
}
395
415
@@ -404,8 +424,8 @@ impl ToJSValConvertible for f64 {
404
424
// https://heycam.github.io/webidl/#es-double
405
425
impl FromJSValConvertible for f64 {
406
426
type Config = ( ) ;
407
- unsafe fn from_jsval ( cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < f64 , ( ) > {
408
- ToNumber ( cx, val)
427
+ unsafe fn from_jsval ( cx : * mut JSContext , val : HandleValue , _option : ( ) ) -> Result < ConversionResult < f64 > , ( ) > {
428
+ ToNumber ( cx, val) . map ( ConversionResult :: Success )
409
429
}
410
430
}
411
431
@@ -451,21 +471,21 @@ impl ToJSValConvertible for String {
451
471
// https://heycam.github.io/webidl/#es-USVString
452
472
impl FromJSValConvertible for String {
453
473
type Config = ( ) ;
454
- unsafe fn from_jsval ( cx : * mut JSContext , value : HandleValue , _: ( ) ) -> Result < String , ( ) > {
474
+ unsafe fn from_jsval ( cx : * mut JSContext , value : HandleValue , _: ( ) ) -> Result < ConversionResult < String > , ( ) > {
455
475
let jsstr = ToString ( cx, value) ;
456
476
if jsstr. is_null ( ) {
457
477
debug ! ( "ToString failed" ) ;
458
478
return Err ( ( ) ) ;
459
479
}
460
480
if JS_StringHasLatin1Chars ( jsstr) {
461
- return Ok ( latin1_to_string ( cx, jsstr) ) ;
481
+ return Ok ( latin1_to_string ( cx, jsstr) ) . map ( ConversionResult :: Success ) ;
462
482
}
463
483
464
484
let mut length = 0 ;
465
485
let chars = JS_GetTwoByteStringCharsAndLength ( cx, ptr:: null ( ) , jsstr, & mut length) ;
466
486
assert ! ( !chars. is_null( ) ) ;
467
487
let char_vec = slice:: from_raw_parts ( chars, length as usize ) ;
468
- Ok ( String :: from_utf16_lossy ( char_vec) )
488
+ Ok ( String :: from_utf16_lossy ( char_vec) ) . map ( ConversionResult :: Success )
469
489
}
470
490
}
471
491
@@ -491,12 +511,14 @@ impl<T: FromJSValConvertible> FromJSValConvertible for Option<T> {
491
511
unsafe fn from_jsval ( cx : * mut JSContext ,
492
512
value : HandleValue ,
493
513
option : T :: Config )
494
- -> Result < Option < T > , ( ) > {
514
+ -> Result < ConversionResult < Option < T > > , ( ) > {
495
515
if value. get ( ) . is_null_or_undefined ( ) {
496
- Ok ( None )
516
+ Ok ( ConversionResult :: Success ( None ) )
497
517
} else {
498
- let result: Result < T , ( ) > = FromJSValConvertible :: from_jsval ( cx, value, option) ;
499
- result. map ( Some )
518
+ Ok ( match try!( FromJSValConvertible :: from_jsval ( cx, value, option) ) {
519
+ ConversionResult :: Success ( v) => ConversionResult :: Success ( Some ( v) ) ,
520
+ ConversionResult :: Failure ( v) => ConversionResult :: Failure ( v) ,
521
+ } )
500
522
}
501
523
}
502
524
}
@@ -553,7 +575,7 @@ impl<C: Clone, T: FromJSValConvertible<Config=C>> FromJSValConvertible for Vec<T
553
575
unsafe fn from_jsval ( cx : * mut JSContext ,
554
576
value : HandleValue ,
555
577
option : C )
556
- -> Result < Vec < T > , ( ) > {
578
+ -> Result < ConversionResult < Vec < T > > , ( ) > {
557
579
let mut iterator = ForOfIterator {
558
580
cx_ : cx,
559
581
iterator : RootedObject :: new_unrooted ( ptr:: null_mut ( ) ) ,
@@ -579,10 +601,13 @@ impl<C: Clone, T: FromJSValConvertible<Config=C>> FromJSValConvertible for Vec<T
579
601
break ;
580
602
}
581
603
582
- ret. push ( try!( T :: from_jsval ( cx, val. handle ( ) , option. clone ( ) ) ) ) ;
604
+ ret. push ( match try!( T :: from_jsval ( cx, val. handle ( ) , option. clone ( ) ) ) {
605
+ ConversionResult :: Success ( v) => v,
606
+ ConversionResult :: Failure ( e) => return Ok ( ConversionResult :: Failure ( e) ) ,
607
+ } ) ;
583
608
}
584
609
585
- Ok ( ret)
610
+ Ok ( ret) . map ( ConversionResult :: Success )
586
611
}
587
612
}
588
613
0 commit comments