1
1
use std:: { i32, i64, u32, u64, f32} ;
2
2
use std:: io;
3
- use std:: mem;
4
3
use byteorder:: { LittleEndian , ReadBytesExt , WriteBytesExt } ;
5
4
use interpreter:: Error ;
6
5
use interpreter:: variable:: VariableType ;
@@ -54,9 +53,9 @@ pub trait TransmuteInto<T> {
54
53
55
54
/// Convert from and to little endian.
56
55
pub trait LittleEndianConvert where Self : Sized {
57
- /// Convert to little endian bufer .
56
+ /// Convert to little endian buffer .
58
57
fn into_little_endian ( self ) -> Vec < u8 > ;
59
- /// Convert from little endian bufer .
58
+ /// Convert from little endian buffer .
60
59
fn from_little_endian ( buffer : Vec < u8 > ) -> Result < Self , Error > ;
61
60
}
62
61
@@ -124,12 +123,12 @@ impl RuntimeValue {
124
123
125
124
/// Creates new value by interpreting passed u32 as f32.
126
125
pub fn decode_f32 ( val : u32 ) -> Self {
127
- RuntimeValue :: F32 ( val . transmute_into ( ) )
126
+ RuntimeValue :: F32 ( f32_from_bits ( val ) )
128
127
}
129
128
130
129
/// Creates new value by interpreting passed u64 as f64.
131
130
pub fn decode_f64 ( val : u64 ) -> Self {
132
- RuntimeValue :: F64 ( val . transmute_into ( ) )
131
+ RuntimeValue :: F64 ( f64_from_bits ( val ) )
133
132
}
134
133
135
134
/// Returns true if value is null.
@@ -224,7 +223,6 @@ impl TryInto<f32, Error> for RuntimeValue {
224
223
impl TryInto < f64 , Error > for RuntimeValue {
225
224
fn try_into ( self ) -> Result < f64 , Error > {
226
225
match self {
227
- //RuntimeValue::F32(val) => Some(val as f64),
228
226
RuntimeValue :: F64 ( val) => Ok ( val) ,
229
227
_ => Err ( Error :: Value ( format ! ( "64-bit float value expected" ) ) ) ,
230
228
}
@@ -234,9 +232,7 @@ impl TryInto<f64, Error> for RuntimeValue {
234
232
impl TryInto < u32 , Error > for RuntimeValue {
235
233
fn try_into ( self ) -> Result < u32 , Error > {
236
234
match self {
237
- RuntimeValue :: I32 ( val) => Ok ( unsafe {
238
- mem:: transmute ( val)
239
- } ) ,
235
+ RuntimeValue :: I32 ( val) => Ok ( val as u32 ) ,
240
236
_ => Err ( Error :: Value ( format ! ( "32-bit int value expected" ) ) ) ,
241
237
}
242
238
}
@@ -245,9 +241,7 @@ impl TryInto<u32, Error> for RuntimeValue {
245
241
impl TryInto < u64 , Error > for RuntimeValue {
246
242
fn try_into ( self ) -> Result < u64 , Error > {
247
243
match self {
248
- RuntimeValue :: I64 ( val) => Ok ( unsafe {
249
- mem:: transmute ( val)
250
- } ) ,
244
+ RuntimeValue :: I64 ( val) => Ok ( val as u64 ) ,
251
245
_ => Err ( Error :: Value ( format ! ( "64-bit int value expected" ) ) ) ,
252
246
}
253
247
}
@@ -347,39 +341,48 @@ impl_transmute_into_self!(i64);
347
341
impl_transmute_into_self ! ( f32 ) ;
348
342
impl_transmute_into_self ! ( f64 ) ;
349
343
350
- macro_rules! impl_transmute_into {
344
+ macro_rules! impl_transmute_into_as {
351
345
( $from: ident, $into: ident) => {
352
346
impl TransmuteInto <$into> for $from {
353
347
fn transmute_into( self ) -> $into {
354
- unsafe {
355
- mem:: transmute( self )
356
- }
348
+ self as $into
357
349
}
358
350
}
359
351
}
360
352
}
361
353
362
- impl_transmute_into ! ( i8 , u8 ) ;
363
- impl_transmute_into ! ( u8 , i8 ) ;
364
- impl_transmute_into ! ( i32 , u32 ) ;
365
- impl_transmute_into ! ( u32 , i32 ) ;
366
- impl_transmute_into ! ( u32 , f32 ) ;
367
- impl_transmute_into ! ( i32 , f32 ) ;
368
- impl_transmute_into ! ( f32 , i32 ) ;
369
- impl_transmute_into ! ( i64 , u64 ) ;
370
- impl_transmute_into ! ( u64 , i64 ) ;
371
- impl_transmute_into ! ( u64 , f64 ) ;
372
- impl_transmute_into ! ( i64 , f64 ) ;
373
- impl_transmute_into ! ( f64 , i64 ) ;
354
+ impl_transmute_into_as ! ( i8 , u8 ) ;
355
+ impl_transmute_into_as ! ( u8 , i8 ) ;
356
+ impl_transmute_into_as ! ( i32 , u32 ) ;
357
+ impl_transmute_into_as ! ( u32 , i32 ) ;
358
+ impl_transmute_into_as ! ( i64 , u64 ) ;
359
+ impl_transmute_into_as ! ( u64 , i64 ) ;
360
+
361
+ // TODO: rewrite these safely when `f32/f32::to_bits/from_bits` stabilized.
362
+ impl TransmuteInto < i32 > for f32 {
363
+ fn transmute_into ( self ) -> i32 { unsafe { :: std:: mem:: transmute ( self ) } }
364
+ }
365
+
366
+ impl TransmuteInto < i64 > for f64 {
367
+ fn transmute_into ( self ) -> i64 { unsafe { :: std:: mem:: transmute ( self ) } }
368
+ }
369
+
370
+ impl TransmuteInto < f32 > for i32 {
371
+ fn transmute_into ( self ) -> f32 { f32_from_bits ( self as _ ) }
372
+ }
373
+
374
+ impl TransmuteInto < f64 > for i64 {
375
+ fn transmute_into ( self ) -> f64 { f64_from_bits ( self as _ ) }
376
+ }
374
377
375
378
impl LittleEndianConvert for i8 {
376
379
fn into_little_endian ( self ) -> Vec < u8 > {
377
- vec ! [ self . transmute_into ( ) ]
380
+ vec ! [ self as u8 ]
378
381
}
379
382
380
383
fn from_little_endian ( buffer : Vec < u8 > ) -> Result < Self , Error > {
381
384
buffer. get ( 0 )
382
- . map ( |v| v . transmute_into ( ) )
385
+ . map ( |v| * v as i8 )
383
386
. ok_or ( Error :: Value ( "invalid little endian buffer" . into ( ) ) )
384
387
}
385
388
}
@@ -469,33 +472,69 @@ impl LittleEndianConvert for i64 {
469
472
impl LittleEndianConvert for f32 {
470
473
fn into_little_endian ( self ) -> Vec < u8 > {
471
474
let mut vec = Vec :: with_capacity ( 4 ) ;
472
- vec. write_i32 :: < LittleEndian > ( self . transmute_into ( ) )
473
- . expect ( "i32 is written without any errors" ) ;
475
+ vec. write_f32 :: < LittleEndian > ( self )
476
+ . expect ( "f32 is written without any errors" ) ;
474
477
vec
475
478
}
476
479
477
480
fn from_little_endian ( buffer : Vec < u8 > ) -> Result < Self , Error > {
478
- io:: Cursor :: new ( buffer) . read_i32 :: < LittleEndian > ( )
479
- . map ( TransmuteInto :: transmute_into )
481
+ io:: Cursor :: new ( buffer) . read_u32 :: < LittleEndian > ( )
482
+ . map ( f32_from_bits )
480
483
. map_err ( |e| Error :: Value ( e. to_string ( ) ) )
481
484
}
482
485
}
483
486
484
487
impl LittleEndianConvert for f64 {
485
488
fn into_little_endian ( self ) -> Vec < u8 > {
486
489
let mut vec = Vec :: with_capacity ( 8 ) ;
487
- vec. write_i64 :: < LittleEndian > ( self . transmute_into ( ) )
490
+ vec. write_f64 :: < LittleEndian > ( self )
488
491
. expect ( "i64 is written without any errors" ) ;
489
492
vec
490
493
}
491
494
492
495
fn from_little_endian ( buffer : Vec < u8 > ) -> Result < Self , Error > {
493
- io:: Cursor :: new ( buffer) . read_i64 :: < LittleEndian > ( )
494
- . map ( TransmuteInto :: transmute_into )
496
+ io:: Cursor :: new ( buffer) . read_u64 :: < LittleEndian > ( )
497
+ . map ( f64_from_bits )
495
498
. map_err ( |e| Error :: Value ( e. to_string ( ) ) )
496
499
}
497
500
}
498
501
502
+ // Convert u32 to f32 safely, masking out sNAN
503
+ fn f32_from_bits ( mut v : u32 ) -> f32 {
504
+ const EXP_MASK : u32 = 0x7F800000 ;
505
+ const QNAN_MASK : u32 = 0x00400000 ;
506
+ const FRACT_MASK : u32 = 0x007FFFFF ;
507
+
508
+ if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
509
+ // If we have a NaN value, we
510
+ // convert signaling NaN values to quiet NaN
511
+ // by setting the the highest bit of the fraction
512
+ // TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
513
+ // or `f32::from_bits` stabilized.
514
+ v |= QNAN_MASK ;
515
+ }
516
+
517
+ unsafe { :: std:: mem:: transmute ( v) }
518
+ }
519
+
520
+ // Convert u64 to f64 safely, masking out sNAN
521
+ fn f64_from_bits ( mut v : u64 ) -> f64 {
522
+ const EXP_MASK : u64 = 0x7FF0000000000000 ;
523
+ const QNAN_MASK : u64 = 0x0001000000000000 ;
524
+ const FRACT_MASK : u64 = 0x000FFFFFFFFFFFFF ;
525
+
526
+ if v & EXP_MASK == EXP_MASK && v & FRACT_MASK != 0 {
527
+ // If we have a NaN value, we
528
+ // convert signaling NaN values to quiet NaN
529
+ // by setting the the highest bit of the fraction
530
+ // TODO: remove when https://github.com/BurntSushi/byteorder/issues/71 closed.
531
+ // or `f64::from_bits` stabilized.
532
+ v |= QNAN_MASK ;
533
+ }
534
+
535
+ unsafe { :: std:: mem:: transmute ( v) }
536
+ }
537
+
499
538
macro_rules! impl_integer_arithmetic_ops {
500
539
( $type: ident) => {
501
540
impl ArithmeticOps <$type> for $type {
0 commit comments