tower_vm/interpreter/
value.rs

1use crate::TypeFlag;
2
3#[derive(Debug, Clone, Copy)]
4pub struct Value {
5    pub ty: TypeFlag,
6    pub data: u64,
7}
8
9impl Value {
10    pub fn to_code(self) -> Vec<u8> {
11        // trim data bytes to type size
12        self.data.to_le_bytes()[..self.ty.size()].to_vec()
13    }
14
15    pub fn from_code(ty: TypeFlag, code: &[u8]) -> Self {
16        let mut data = [0; 8];
17        if code.len() != ty.size() {
18            panic!("{:?} expects {} bytes, got {}", ty, ty.size(), code.len());
19        }else if code.len() != 8 {
20            let mut idx = 0;
21            for byte in code {
22                data[idx] = *byte;
23                idx += 1;
24            }
25        }else{
26            data.copy_from_slice(code);
27        }
28        Self {
29            ty,
30            data: u64::from_le_bytes(data),
31        }
32    }
33
34    pub fn to_stack(self) -> u64 {
35        self.data
36    }
37
38    pub fn from_stack(ty: TypeFlag, raw: u64) -> Self {
39        Self { ty, data: raw }
40    }
41
42    pub fn to_string(self) -> String {
43        self.into()
44    }
45}
46
47macro_rules! impl_from_value {
48    ($from_type:ty, $type_flag:ident) => {
49        impl From<$from_type> for Value {
50            fn from(value: $from_type) -> Self {
51                Self {
52                    ty: TypeFlag::$type_flag,
53                    data: value as u64,
54                }
55            }
56        }
57    };
58}
59
60
61
62impl_from_value!(i8, I8);
63impl_from_value!(i16, I16);
64impl_from_value!(i32, I32);
65impl_from_value!(i64, I64);
66
67impl_from_value!(char, Char);
68impl_from_value!(bool, Bool);
69
70impl_from_value!(u8, U8);
71impl_from_value!(u16, U16);
72impl_from_value!(u32, U32);
73impl_from_value!(u64, U64);
74
75
76
77impl From<f32> for Value {
78    fn from(value: f32) -> Self {
79        Self {
80            ty: TypeFlag::F32,
81            data: value.to_bits() as u64,
82        }
83    }
84}
85
86impl From<f64> for Value {
87    fn from(value: f64) -> Self {
88        Self {
89            ty: TypeFlag::F64,
90            data: value.to_bits(),
91        }
92    }
93}
94
95macro_rules! impl_try_into_value {
96    ($to_type:ty, $type_flag:ident) => {
97        impl TryInto<$to_type> for Value {
98            type Error = &'static str;
99
100            fn try_into(self) -> Result<$to_type, Self::Error> {
101                if self.ty == TypeFlag::$type_flag {
102                    Ok(self.data as $to_type)
103                } else {
104                    Err("invalid type")
105                }
106            }
107        }
108
109        impl TryInto<$to_type> for &Value {
110            type Error = &'static str;
111
112            fn try_into(self) -> Result<$to_type, Self::Error> {
113                if self.ty == TypeFlag::$type_flag {
114                    Ok(self.data as $to_type)
115                } else {
116                    Err("invalid type")
117                }
118            }
119        }
120    };
121}
122
123impl_try_into_value!(i8, I8);
124impl_try_into_value!(i16, I16);
125impl_try_into_value!(i32, I32);
126impl_try_into_value!(i64, I64);
127
128impl TryInto<char> for Value {
129    type Error = &'static str;
130
131    fn try_into(self) -> Result<char, Self::Error> {
132        if self.ty == TypeFlag::Char {
133            Ok(char::from_u32(self.data as u32).unwrap())
134        } else {
135            Err("invalid type")
136        }
137    }
138}
139
140impl TryInto<char> for &Value {
141    type Error = &'static str;
142
143    fn try_into(self) -> Result<char, Self::Error> {
144        if self.ty == TypeFlag::Char {
145            Ok(char::from_u32(self.data as u32).unwrap())
146        } else {
147            Err("invalid type")
148        }
149    }
150}
151
152impl TryInto<bool> for Value {
153    type Error = &'static str;
154
155    fn try_into(self) -> Result<bool, Self::Error> {
156        if self.ty == TypeFlag::Bool {
157            Ok(self.data != 0)
158        } else {
159            Err("invalid type")
160        }
161    }
162}
163
164impl TryInto<bool> for &Value {
165    type Error = &'static str;
166
167    fn try_into(self) -> Result<bool, Self::Error> {
168        if self.ty == TypeFlag::Bool {
169            Ok(self.data != 0)
170        } else {
171            Err("invalid type")
172        }
173    }
174}
175
176impl_try_into_value!(u8, U8);
177impl_try_into_value!(u16, U16);
178impl_try_into_value!(u32, U32);
179impl_try_into_value!(u64, U64);
180
181impl TryInto<f32> for Value {
182    type Error = &'static str;
183
184    fn try_into(self) -> Result<f32, Self::Error> {
185        if self.ty == TypeFlag::F32 {
186            Ok(f32::from_bits(self.data as u32))
187        } else {
188            Err("invalid type")
189        }
190    }
191}
192
193impl TryInto<f32> for &Value {
194    type Error = &'static str;
195
196    fn try_into(self) -> Result<f32, Self::Error> {
197        if self.ty == TypeFlag::F32 {
198            Ok(f32::from_bits(self.data as u32))
199        } else {
200            Err("invalid type")
201        }
202    }
203}
204
205impl TryInto<f64> for Value {
206    type Error = &'static str;
207
208    fn try_into(self) -> Result<f64, Self::Error> {
209        if self.ty == TypeFlag::F64 {
210            Ok(f64::from_bits(self.data))
211        } else {
212            Err("invalid type")
213        }
214    }
215}
216
217impl TryInto<f64> for &Value {
218    type Error = &'static str;
219
220    fn try_into(self) -> Result<f64, Self::Error> {
221        if self.ty == TypeFlag::F64 {
222            Ok(f64::from_bits(self.data))
223        } else {
224            Err("invalid type")
225        }
226    }
227}
228
229macro_rules! impl_arith_ops {
230    ($trait:path, $fn_name:ident, $op:tt) => {
231        impl $trait for Value {
232            type Output = Self;
233
234                fn $fn_name(self, rhs: Self) -> Self::Output {
235                    use TypeFlag::*;
236                    match (self.ty, rhs.ty) {
237                        (I8, I8) => {
238                            let lhs: i8 = self.try_into().unwrap();
239                            let rhs: i8 = rhs.try_into().unwrap();
240                            (lhs $op rhs).into()
241                        }
242                        (I16, I16) => {
243                            let lhs: i16 = self.try_into().unwrap();
244                            let rhs: i16 = rhs.try_into().unwrap();
245                            (lhs $op rhs).into()
246                        }
247                        (I32, I32) => {
248                            let lhs: i32 = self.try_into().unwrap();
249                            let rhs: i32 = rhs.try_into().unwrap();
250                            (lhs $op rhs).into()
251                        }
252                        (I64, I64) => {
253                            let lhs: i64 = self.try_into().unwrap();
254                            let rhs: i64 = rhs.try_into().unwrap();
255                            (lhs $op rhs).into()
256                        }
257                        (F32, F32) => {
258                            let lhs: f32 = self.try_into().unwrap();
259                            let rhs: f32 = rhs.try_into().unwrap();
260                            (lhs $op rhs).into()
261                        }
262                        (F64, F64) => {
263                            let lhs: f64 = self.try_into().unwrap();
264                            let rhs: f64 = rhs.try_into().unwrap();
265                            (lhs $op rhs).into()
266                        }
267                        (U8, U8) => {
268                            let lhs: u8 = self.try_into().unwrap();
269                            let rhs: u8 = rhs.try_into().unwrap();
270                            (lhs $op rhs).into()
271                        }
272                        (U16, U16) => {
273                            let lhs: u16 = self.try_into().unwrap();
274                            let rhs: u16 = rhs.try_into().unwrap();
275                            (lhs $op rhs).into()
276                        }
277                        (U32, U32) => {
278                            let lhs: u32 = self.try_into().unwrap();
279                            let rhs: u32 = rhs.try_into().unwrap();
280                            (lhs $op rhs).into()
281                        }
282                        (U64, U64) => {
283                            let lhs: u64 = self.try_into().unwrap();
284                            let rhs: u64 = rhs.try_into().unwrap();
285                            (lhs $op rhs).into()
286                        }
287                        _ => panic!("invalid types"),
288                    }
289                }
290            }
291    };
292}
293
294impl_arith_ops!(std::ops::Add, add, +);
295impl_arith_ops!(std::ops::Sub, sub, -);
296impl_arith_ops!(std::ops::Mul, mul, *);
297impl_arith_ops!(std::ops::Div, div, /);
298impl_arith_ops!(std::ops::Rem, rem, %);
299
300macro_rules! impl_bit_ops {
301    ($trait:path, $fn_name:ident, $op:tt) => {
302        impl $trait for Value {
303            type Output = Self;
304
305            fn $fn_name(self, rhs: Self) -> Self::Output {
306                use TypeFlag::*;
307
308                match (self.ty, rhs.ty) {
309                    (I8, I8) => {
310                        let lhs: i8 = self.try_into().unwrap();
311                        let rhs: i8 = rhs.try_into().unwrap();
312                        (lhs $op rhs).into()
313                    }
314                    (I16, I16) => {
315                        let lhs: i16 = self.try_into().unwrap();
316                        let rhs: i16 = rhs.try_into().unwrap();
317                        (lhs $op rhs).into()
318                    }
319                    (I32, I32) => {
320                        let lhs: i32 = self.try_into().unwrap();
321                        let rhs: i32 = rhs.try_into().unwrap();
322                        (lhs $op rhs).into()
323                    }
324                    (I64, I64) => {
325                        let lhs: i64 = self.try_into().unwrap();
326                        let rhs: i64 = rhs.try_into().unwrap();
327                        (lhs $op rhs).into()
328                    }
329                    (U8, U8) => {
330                        let lhs: u8 = self.try_into().unwrap();
331                        let rhs: u8 = rhs.try_into().unwrap();
332                        (lhs $op rhs).into()
333                    }
334                    (U16, U16) => {
335                        let lhs: u16 = self.try_into().unwrap();
336                        let rhs: u16 = rhs.try_into().unwrap();
337                        (lhs $op rhs).into()
338                    }
339                    (U32, U32) => {
340                        let lhs: u32 = self.try_into().unwrap();
341                        let rhs: u32 = rhs.try_into().unwrap();
342                        (lhs $op rhs).into()
343                    }
344                    (U64, U64) => {
345                        let lhs: u64 = self.try_into().unwrap();
346                        let rhs: u64 = rhs.try_into().unwrap();
347                        (lhs $op rhs).into()
348                    }
349                    _ => panic!("invalid types"),
350                }
351            }
352        }
353    };
354}
355
356impl_bit_ops!(std::ops::BitAnd, bitand, &);
357impl_bit_ops!(std::ops::BitOr, bitor, |);
358impl_bit_ops!(std::ops::BitXor, bitxor, ^);
359impl_bit_ops!(std::ops::Shl, shl, <<);
360impl_bit_ops!(std::ops::Shr, shr, >>);
361
362impl std::ops::Not for Value {
363    type Output = Self;
364
365    fn not(self) -> Self::Output {
366        use TypeFlag::*;
367
368        match self.ty {
369            I8 => {
370                let lhs: i8 = self.try_into().unwrap();
371                (!lhs).into()
372            }
373            I16 => {
374                let lhs: i16 = self.try_into().unwrap();
375                (!lhs).into()
376            }
377            I32 => {
378                let lhs: i32 = self.try_into().unwrap();
379                (!lhs).into()
380            }
381            I64 => {
382                let lhs: i64 = self.try_into().unwrap();
383                (!lhs).into()
384            }
385            U8 => {
386                let lhs: u8 = self.try_into().unwrap();
387                (!lhs).into()
388            }
389            U16 => {
390                let lhs: u16 = self.try_into().unwrap();
391                (!lhs).into()
392            }
393            U32 => {
394                let lhs: u32 = self.try_into().unwrap();
395                (!lhs).into()
396            }
397            U64 => {
398                let lhs: u64 = self.try_into().unwrap();
399                (!lhs).into()
400            }
401            Bool => {
402                let lhs: bool = self.try_into().unwrap();
403                (!lhs).into()
404            }
405            _ => panic!("invalid types"),
406        }
407    }
408}
409
410impl std::ops::Neg for Value {
411    type Output = Self;
412
413    fn neg(self) -> Self::Output {
414        use TypeFlag::*;
415
416        match self.ty {
417            I8 => {
418                let lhs: i8 = self.try_into().unwrap();
419                (-lhs).into()
420            }
421            I16 => {
422                let lhs: i16 = self.try_into().unwrap();
423                (-lhs).into()
424            }
425            I32 => {
426                let lhs: i32 = self.try_into().unwrap();
427                (-lhs).into()
428            }
429            I64 => {
430                let lhs: i64 = self.try_into().unwrap();
431                (-lhs).into()
432            }
433            F32 => {
434                let lhs: f32 = self.try_into().unwrap();
435                (-lhs).into()
436            }
437            F64 => {
438                let lhs: f64 = self.try_into().unwrap();
439                (-lhs).into()
440            }
441            _ => panic!("invalid types"),
442        }
443    }
444}
445
446impl std::cmp::PartialEq for Value {
447    fn eq(&self, other: &Self) -> bool {
448        if self.ty == other.ty {
449            return self.data == other.data;
450        }
451        return false;
452    }
453
454    fn ne(&self, other: &Self) -> bool {
455        if self.ty == other.ty {
456            return self.data != other.data;
457        }
458        return true;
459    }
460}
461
462impl std::cmp::PartialOrd for Value {
463    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
464        if self.ty == other.ty {
465            return self.data.partial_cmp(&other.data);
466        }
467        return None;
468    }
469}
470
471
472impl std::fmt::Display for Value {
473    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
474        use TypeFlag::*;
475
476        match self.ty {
477            I8 => {
478                let val: i8 = self.try_into().unwrap();
479                write!(f, "{}", val)
480            },
481            I16 => {
482                let val: i16 = self.try_into().unwrap();
483                write!(f, "{}", val)
484            },
485            I32 => {
486                let val: i32 = self.try_into().unwrap();
487                write!(f, "{}", val)
488            },
489            I64 => {
490                let val: i64 = self.try_into().unwrap();
491                write!(f, "{}", val)
492            },
493            U8 => {
494                let val: u8 = self.try_into().unwrap();
495                write!(f, "{}", val)
496            },
497            U16 => {
498                let val: u16 = self.try_into().unwrap();
499                write!(f, "{}", val)
500            },
501            U32 => {
502                let val: u32 = self.try_into().unwrap();
503                write!(f, "{}", val)
504            },
505            U64 => {
506                let val: u64 = self.try_into().unwrap();
507                write!(f, "{}", val)
508            },
509            F32 => {
510                let val: f32 = self.try_into().unwrap();
511                write!(f, "{}", val)
512            },
513            F64 => {
514                let val: f64 = self.try_into().unwrap();
515                write!(f, "{}", val)
516            },
517            Bool => {
518                let val: bool = self.try_into().unwrap();
519                write!(f, "{}", val)
520            },
521            Char => {
522                let val: char = self.try_into().unwrap();
523                write!(f, "{}", val)
524            },
525        }
526    }
527}
528
529impl Into<String> for Value {
530    fn into(self) -> String {
531        format!("{}", self)
532    }
533}
534
535
536
537#[cfg(test)]
538mod tests {
539    use super::*;
540
541    // value lifecycle tests
542    // STEPS:
543    // 1. init primitive value ie. i8, i16, i32, i64, f32, f64, bool, char, u8, u16, u32, u64
544    // 2. convert to value
545    // 3. convert to [u8] using to_code() (this is used when values are inlined in the bytecode)
546    // 4. convert to value using from_code() (this is used when values are take from bytecode then pushed to the stack)
547    // 5. convert to u64 using to_stack() (this is used when values are pushed to the stack)
548    // 6. convert back to value with from_stack() and a type flag (this is used when values are popped from the stack)
549    // 7. convert back to primitive value
550    // 8. assert that the primitive value is equal to the initial value
551    // lossless conversions.
552
553    macro_rules! lifecycle_test {
554        ($type:ty, $flag:expr, $init:expr) => {
555            let init: $type = $init;
556            let value = Value::from(init);
557            let code: &[u8] = &value.to_code();
558            let decode = Value::from_code($flag, code);
559            let stack_push = decode.to_stack();
560            let stack_pop = Value::from_stack($flag, stack_push);
561            let prim_test: $type = stack_pop.try_into().unwrap();
562            assert_eq!(prim_test, init);
563        };
564    }
565
566    #[test]
567    fn test_i8_lifecycle() {
568        lifecycle_test!(i8, TypeFlag::I8, -100);
569        lifecycle_test!(i8, TypeFlag::I8, 126);
570    }
571
572    #[test]
573    fn test_i16_lifecycle() {
574        lifecycle_test!(i16, TypeFlag::I16, -20);
575        lifecycle_test!(i16, TypeFlag::I16, 12345);
576    }
577
578    #[test]
579    fn test_i32_lifecycle() {
580        lifecycle_test!(i32, TypeFlag::I32, 7895);
581        lifecycle_test!(i32, TypeFlag::I32, 1234567890);
582    }
583
584    #[test]
585    fn test_i64_lifecycle() {
586        lifecycle_test!(i64, TypeFlag::I64, 1234567890);
587        lifecycle_test!(i64, TypeFlag::I64, 1234567890123456789);
588    }
589
590    #[test]
591    fn test_f32_lifecycle() {
592        lifecycle_test!(f32, TypeFlag::F32, std::f32::consts::PI);
593        lifecycle_test!(f32, TypeFlag::F32, std::f32::consts::E);
594    }
595
596    #[test]
597    fn test_f64_lifecycle() {
598        lifecycle_test!(f64, TypeFlag::F64, std::f64::consts::PI);
599        lifecycle_test!(f64, TypeFlag::F64, std::f64::consts::E);
600    }
601
602    #[test]
603    fn test_bool_lifecycle() {
604        lifecycle_test!(bool, TypeFlag::Bool, true);
605        lifecycle_test!(bool, TypeFlag::Bool, false);
606    }
607
608    #[test]
609    fn test_char_lifecycle() {
610        lifecycle_test!(char, TypeFlag::Char, 'a');
611        lifecycle_test!(char, TypeFlag::Char, 'b');
612        lifecycle_test!(char, TypeFlag::Char, 'c');
613    }
614
615    #[test]
616    fn test_u8_lifecycle() {
617        lifecycle_test!(u8, TypeFlag::U8, 255);
618        lifecycle_test!(u8, TypeFlag::U8, 0);
619        lifecycle_test!(u8, TypeFlag::U8, 127);
620    }
621
622    #[test]
623    fn test_u16_lifecycle() {
624        lifecycle_test!(u16, TypeFlag::U16, 65535);
625        lifecycle_test!(u16, TypeFlag::U16, 0);
626        lifecycle_test!(u16, TypeFlag::U16, 32767);
627    }
628
629    #[test]
630    fn test_u32_lifecycle() {
631        lifecycle_test!(u32, TypeFlag::U32, 4294967295);
632        lifecycle_test!(u32, TypeFlag::U32, 0);
633        lifecycle_test!(u32, TypeFlag::U32, 2147483647);
634    }
635
636    #[test]
637    fn test_u64_lifecycle() {
638        lifecycle_test!(u64, TypeFlag::U64, 18446744073709551615);
639        lifecycle_test!(u64, TypeFlag::U64, 0);
640        lifecycle_test!(u64, TypeFlag::U64, 9223372036854775807);
641    }
642
643    // std::ops tests
644    // add steps:
645    // 1. create two values lhs and rhs
646    // 2. create a value called expected that is the known result of lhs + rhs
647    // 3. create a value called actual that is lhs + rhs
648    // 4. assert that expected == actual
649    macro_rules! bin_test {
650        ($type:ty, $lhs:expr, $rhs:expr, $op:tt) => {
651            let lhs = Value::from($lhs);
652            let rhs = Value::from($rhs);
653            let expected = Value::from($lhs $op $rhs);
654            let actual = lhs $op rhs;
655            assert_eq!(expected, actual);
656        };
657    }
658
659    macro_rules! all_arith_tests {
660        ($type:ty, $lhs:expr, $rhs:expr) => {
661            bin_test!($type, $lhs, $rhs, +);
662
663            bin_test!($type, $lhs, $rhs, -);
664
665            bin_test!($type, $lhs, $rhs, *);
666
667            bin_test!($type, $lhs, $rhs, /);
668
669            bin_test!($type, $lhs, $rhs, %);
670        };
671    }
672
673    #[test]
674    fn test_i8_arith() {
675        all_arith_tests!(i8, 2, 5);
676        all_arith_tests!(i8, 100, 1);
677        all_arith_tests!(i8, 20, 4);
678    }
679
680    #[test]
681    fn test_i16_artih() {
682        all_arith_tests!(i16, 20, 5);
683        all_arith_tests!(i16, 100, 20);
684        all_arith_tests!(i16, 3, 4);
685    }
686
687    #[test]
688    fn test_i32_arith() {
689        all_arith_tests!(i32, 88, 44);
690        all_arith_tests!(i32, 56, 8);
691        all_arith_tests!(i32, 100, 5);
692    }
693
694    #[test]
695    fn test_i64_arith() {
696        all_arith_tests!(i64, 100, 5);
697        all_arith_tests!(i64, 648, 111);
698        all_arith_tests!(i64, 86, 4);
699    }
700
701    #[test]
702    fn test_f32_arith() {
703        all_arith_tests!(f32, std::f32::consts::PI, 1.3456f32);
704        all_arith_tests!(f32, std::f32::consts::E, 13.7689f32);
705        all_arith_tests!(f32, 1.067f32, 1.12310f32);
706
707    }
708
709    #[test]
710    fn test_f64_arith() {
711        all_arith_tests!(f64, std::f64::consts::PI, 1.3456f64);
712        all_arith_tests!(f64, std::f64::consts::E, 13.7689f64);
713        all_arith_tests!(f64, 1.067f64, 1.12310f64);
714    }
715
716
717    #[test]
718    fn test_u8_arith() {
719        all_arith_tests!(u8, 100, 5);
720        all_arith_tests!(u8, 255, 1);
721        all_arith_tests!(u8, 86, 4);
722    }
723
724    #[test]
725    fn test_u16_arith() {
726        all_arith_tests!(u16, 100, 5);
727        all_arith_tests!(u16, 65535, 1);
728        all_arith_tests!(u16, 86, 4);
729    }
730
731    #[test]
732    fn test_u32_arith() {
733        all_arith_tests!(u32, 100, 5);
734        all_arith_tests!(u32, 586858, 1);
735        all_arith_tests!(u32, 86, 4);
736    }
737
738    #[test]
739    fn test_u64_arith() {
740        all_arith_tests!(u64, 100, 5);
741        all_arith_tests!(u64, 586858, 1);
742        all_arith_tests!(u64, 86, 4);
743    }
744
745    // std::ops::BitAnd tests
746
747    macro_rules! all_bit_tests {
748        ($type:ty, $lhs:expr, $rhs:expr) => {
749            bin_test!($type, $lhs, $rhs, &);
750            bin_test!($type, $lhs, $rhs, |);
751            bin_test!($type, $lhs, $rhs, ^);
752        };
753    }
754    
755    #[test]
756    fn test_i8_bitops() {
757        all_bit_tests!(i8, 2i8, 100i8);
758        all_bit_tests!(i8, 20i8, 4i8);
759        all_bit_tests!(i8, 22i8, 5i8);
760    }
761
762    #[test]
763    fn test_i16_bitops() {
764        all_bit_tests!(i16, 100i16, 101i16);
765        all_bit_tests!(i16, 20i16, 4i16);
766        all_bit_tests!(i16, 22i16, 5i16);
767    }
768
769    #[test]
770    fn test_i32_bitops() {
771        all_bit_tests!(i32, 120i32, 55i32);
772        all_bit_tests!(i32, 20i32, 4i32);
773        all_bit_tests!(i32, 22i32, 5i32);
774    }
775
776    #[test]
777    fn test_i64_bitops() {
778        all_bit_tests!(i64, 100i64, 50i64);
779        all_bit_tests!(i64, 20i64, 4i64);
780        all_bit_tests!(i64, 26i64, 100i64);
781    }
782
783    #[test]
784    fn test_u8_bitops() {
785        all_bit_tests!(u8, 100u8, 50u8);
786        all_bit_tests!(u8, 20u8, 4u8);
787        all_bit_tests!(u8, 2u8, 5u8);
788    }
789
790    #[test]
791    fn test_u16_bitops() {
792        all_bit_tests!(u16, 100u16, 50u16);
793        all_bit_tests!(u16, 20u16, 4u16);
794        all_bit_tests!(u16, 2u16, 5u16);
795    }
796
797    #[test]
798    fn test_u32_bitops() {
799        all_bit_tests!(u32, 100u32, 50u32);
800        all_bit_tests!(u32, 20u32, 4u32);
801        all_bit_tests!(u32, 2u32, 5u32);
802    }
803
804    #[test]
805    fn test_u64_bitops() {
806        all_bit_tests!(u64, 100u64, 50u64);
807        all_bit_tests!(u64, 20u64, 4u64);
808        all_bit_tests!(u64, 2u64, 5u64);
809    }
810    // std::ops::Shl tests
811
812    macro_rules! shift_tests {
813        ($type:ty, $lhs:expr, $rhs:expr) => {
814            bin_test!($type, $lhs, $rhs, <<);
815            bin_test!($type, $lhs, $rhs, >>);
816        };
817    }
818
819    #[test]
820    fn test_i8_shift() {
821        shift_tests!(i8, 100i8, 3i8);
822        shift_tests!(i8, 20i8, 4i8);
823        shift_tests!(i8, 22i8, 5i8);
824    }
825
826    #[test]
827    fn test_i16_shift() {
828        shift_tests!(i16, 100i16, 3i16);
829        shift_tests!(i16, 20i16, 4i16);
830        shift_tests!(i16, 22i16, 5i16);
831    }
832
833    #[test]
834    fn test_i32_shift() {
835        shift_tests!(i32, 100i32, 3i32);
836        shift_tests!(i32, 20i32, 4i32);
837        shift_tests!(i32, 22i32, 5i32);
838    }
839
840    #[test]
841    fn test_i64_shift() {
842        shift_tests!(i64, 100i64, 3i64);
843        shift_tests!(i64, 20i64, 4i64);
844        shift_tests!(i64, 22i64, 5i64);
845    }
846
847    #[test]
848    fn test_u8_shift() {
849        shift_tests!(u8, 100u8, 3u8);
850        shift_tests!(u8, 20u8, 4u8);
851        shift_tests!(u8, 22u8, 5u8);
852    }
853
854    #[test]
855    fn test_u16_shift() {
856        shift_tests!(u16, 100u16, 3u16);
857        shift_tests!(u16, 20u16, 4u16);
858        shift_tests!(u16, 22u16, 5u16);
859    }
860
861    #[test]
862    fn test_u32_shift() {
863        shift_tests!(u32, 100u32, 3u32);
864        shift_tests!(u32, 20u32, 4u32);
865        shift_tests!(u32, 22u32, 5u32);
866    }
867
868    #[test]
869    fn test_u64_shift() {
870        shift_tests!(u64, 100u64, 3u64);
871        shift_tests!(u64, 20u64, 4u64);
872        shift_tests!(u64, 22u64, 5u64);
873    }
874
875    // std::ops::Not tests
876
877    macro_rules! unary_test {
878        ($type:ty, $val:expr, $op:tt) => {
879            let value = Value::from($val);
880            let expected = Value::from($op$val);
881            let actual = $op value;
882            assert_eq!(expected, actual);
883        };
884    }
885
886    macro_rules! not_tests {
887        ($type:ty, $val:expr) => {
888            unary_test!($type, $val, !);
889        };
890    }
891
892    #[test]
893    fn test_i8_not() {
894        not_tests!(i8, 100i8);
895        not_tests!(i8, 20i8);
896        not_tests!(i8, 22i8);
897    }
898
899    #[test]
900    fn test_i16_not() {
901        not_tests!(i16, 1245i16);
902        not_tests!(i16, 1005i16);
903    }
904
905    #[test]
906    fn test_i32_not() {
907        not_tests!(i32, 10000i32);
908        not_tests!(i32, 5000i32);
909    }
910
911    #[test]
912    fn test_i64_not() {
913        not_tests!(i64, 100000i64);
914        not_tests!(i64, 50000i64);
915    }
916
917    #[test]
918    fn test_u8_not() {
919        not_tests!(u8, 100u8);
920        not_tests!(u8, 20u8);
921        not_tests!(u8, std::u8::MAX);
922        not_tests!(u8, std::u8::MIN);
923    }
924
925    #[test]
926    fn test_u16_not() {
927        not_tests!(u16, 1000u16);
928        not_tests!(u16, 2000u16);
929        not_tests!(u16, std::u16::MAX);
930        not_tests!(u16, std::u16::MIN);
931    }
932
933    #[test]
934    fn test_u32_not() {
935        not_tests!(u32, std::u32::MAX);
936        not_tests!(u32, std::u32::MIN);
937    }
938
939    #[test]
940    fn test_u64_not() {
941        not_tests!(u64, std::u64::MAX);
942        not_tests!(u64, std::u64::MIN);
943    }
944
945    #[test]
946    fn test_bool_not() {
947        not_tests!(bool, true);
948        not_tests!(bool, false);
949    }
950
951    // std::ops::Neg tests
952
953    macro_rules! neg_tests {
954        ($type:ty, $val:expr) => {
955            unary_test!($type, $val, -);
956        };
957    }
958    
959
960    #[test]
961    fn test_i8_neg() {
962        neg_tests!(i8, 100i8);
963        neg_tests!(i8, -20i8);
964    }
965
966    #[test]
967    fn test_i16_neg() {
968        neg_tests!(i16, 1245i16);
969        neg_tests!(i16, -1005i16);
970    }
971
972    #[test]
973    fn test_i32_neg() {
974        neg_tests!(i32, 10000i32);
975        neg_tests!(i32, -5000i32);
976    }
977
978    #[test]
979    fn test_i64_neg() {
980        neg_tests!(i64, 100000i64);
981        neg_tests!(i64, -50000i64);
982    }
983
984    #[test]
985    fn test_f32_neg() {
986        neg_tests!(f32, std::f32::consts::PI);
987        neg_tests!(f32, -std::f32::consts::E);
988    }
989
990    #[test]
991    fn test_f64_neg() {
992        neg_tests!(f64, std::f64::consts::PI);
993        neg_tests!(f64, -std::f64::consts::E);
994    }
995
996    #[test]
997    fn test_to_string() {
998        assert_eq!(Value::from(10).to_string(), "10".to_string());
999        assert_eq!(Value::from('c').to_string(), "c".to_string());
1000    }
1001}