@@ -93,13 +93,12 @@ macro_rules! impl_fmt_traits {
93
93
impl_fmt_trait!( $name, $native, Display ) ;
94
94
} ;
95
95
( $name: ident, $native: ident, "unsigned integer" ) => {
96
- impl_fmt_traits!( $name, $native, @all_traits ) ;
96
+ impl_fmt_traits!( $name, $native, @all_types ) ;
97
97
} ;
98
98
( $name: ident, $native: ident, "signed integer" ) => {
99
- impl_fmt_traits!( $name, $native, @all_traits ) ;
99
+ impl_fmt_traits!( $name, $native, @all_types ) ;
100
100
} ;
101
-
102
- ( $name: ident, $native: ident, @all_traits) => {
101
+ ( $name: ident, $native: ident, @all_types) => {
103
102
impl_fmt_trait!( $name, $native, Display ) ;
104
103
impl_fmt_trait!( $name, $native, Octal ) ;
105
104
impl_fmt_trait!( $name, $native, LowerHex ) ;
@@ -108,6 +107,101 @@ macro_rules! impl_fmt_traits {
108
107
} ;
109
108
}
110
109
110
+ macro_rules! impl_ops_traits {
111
+ ( $name: ident, $native: ident, "floating point number" ) => {
112
+ impl_ops_traits!( $name, $native, @all_types) ;
113
+ impl_ops_traits!( $name, $native, @signed_integer_floating_point) ;
114
+ } ;
115
+ ( $name: ident, $native: ident, "unsigned integer" ) => {
116
+ impl_ops_traits!( $name, $native, @signed_unsigned_integer) ;
117
+ impl_ops_traits!( $name, $native, @all_types) ;
118
+ } ;
119
+ ( $name: ident, $native: ident, "signed integer" ) => {
120
+ impl_ops_traits!( $name, $native, @signed_unsigned_integer) ;
121
+ impl_ops_traits!( $name, $native, @signed_integer_floating_point) ;
122
+ impl_ops_traits!( $name, $native, @all_types) ;
123
+ } ;
124
+ ( $name: ident, $native: ident, @signed_unsigned_integer) => {
125
+ impl_ops_traits!( @without_byteorder_swap $name, $native, BitAnd , bitand, BitAndAssign , bitand_assign) ;
126
+ impl_ops_traits!( @without_byteorder_swap $name, $native, BitOr , bitor, BitOrAssign , bitor_assign) ;
127
+ impl_ops_traits!( @without_byteorder_swap $name, $native, BitXor , bitxor, BitXorAssign , bitxor_assign) ;
128
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Shl , shl, ShlAssign , shl_assign) ;
129
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Shr , shr, ShrAssign , shr_assign) ;
130
+
131
+ impl <O > core:: ops:: Not for $name<O > {
132
+ type Output = $name<O >;
133
+
134
+ #[ inline( always) ]
135
+ fn not( self ) -> $name<O > {
136
+ let self_native = $native:: from_ne_bytes( self . 0 ) ;
137
+ $name( ( !self_native) . to_ne_bytes( ) , PhantomData )
138
+ }
139
+ }
140
+ } ;
141
+ ( $name: ident, $native: ident, @signed_integer_floating_point) => {
142
+ impl <O : ByteOrder > core:: ops:: Neg for $name<O > {
143
+ type Output = $name<O >;
144
+
145
+ #[ inline( always) ]
146
+ fn neg( self ) -> $name<O > {
147
+ let self_native: $native = self . get( ) ;
148
+ #[ allow( clippy:: arithmetic_side_effects) ]
149
+ $name:: <O >:: new( -self_native)
150
+ }
151
+ }
152
+ } ;
153
+ ( $name: ident, $native: ident, @all_types) => {
154
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Add , add, AddAssign , add_assign) ;
155
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Div , div, DivAssign , div_assign) ;
156
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Mul , mul, MulAssign , mul_assign) ;
157
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Rem , rem, RemAssign , rem_assign) ;
158
+ impl_ops_traits!( @with_byteorder_swap $name, $native, Sub , sub, SubAssign , sub_assign) ;
159
+ } ;
160
+ ( @with_byteorder_swap $name: ident, $native: ident, $trait: ident, $method: ident, $trait_assign: ident, $method_assign: ident) => {
161
+ impl <O : ByteOrder > core:: ops:: $trait for $name<O > {
162
+ type Output = $name<O >;
163
+
164
+ #[ inline( always) ]
165
+ fn $method( self , rhs: $name<O >) -> $name<O > {
166
+ let self_native: $native = self . get( ) ;
167
+ let rhs_native: $native = rhs. get( ) ;
168
+ let result_native = core:: ops:: $trait:: $method( self_native, rhs_native) ;
169
+ $name:: <O >:: new( result_native)
170
+ }
171
+ }
172
+
173
+ impl <O : ByteOrder > core:: ops:: $trait_assign for $name<O > {
174
+ #[ inline( always) ]
175
+ fn $method_assign( & mut self , rhs: $name<O >) {
176
+ * self = core:: ops:: $trait:: $method( * self , rhs) ;
177
+ }
178
+ }
179
+ } ;
180
+ // Implement traits in terms of the same trait on the native type, but
181
+ // without performing a byte order swap. This only works for bitwise
182
+ // operations like `&`, `|`, etc.
183
+ ( @without_byteorder_swap $name: ident, $native: ident, $trait: ident, $method: ident, $trait_assign: ident, $method_assign: ident) => {
184
+ impl <O : ByteOrder > core:: ops:: $trait for $name<O > {
185
+ type Output = $name<O >;
186
+
187
+ #[ inline( always) ]
188
+ fn $method( self , rhs: $name<O >) -> $name<O > {
189
+ let self_native = $native:: from_ne_bytes( self . 0 ) ;
190
+ let rhs_native = $native:: from_ne_bytes( rhs. 0 ) ;
191
+ let result_native = core:: ops:: $trait:: $method( self_native, rhs_native) ;
192
+ $name( result_native. to_ne_bytes( ) , PhantomData )
193
+ }
194
+ }
195
+
196
+ impl <O : ByteOrder > core:: ops:: $trait_assign for $name<O > {
197
+ #[ inline( always) ]
198
+ fn $method_assign( & mut self , rhs: $name<O >) {
199
+ * self = core:: ops:: $trait:: $method( * self , rhs) ;
200
+ }
201
+ }
202
+ } ;
203
+ }
204
+
111
205
macro_rules! doc_comment {
112
206
( $x: expr, $( $tt: tt) * ) => {
113
207
#[ doc = $x]
@@ -347,6 +441,7 @@ example of how it can be used for parsing UDP packets.
347
441
}
348
442
349
443
impl_fmt_traits!( $name, $native, $number_kind) ;
444
+ impl_ops_traits!( $name, $native, $number_kind) ;
350
445
351
446
impl <O : ByteOrder > Debug for $name<O > {
352
447
#[ inline]
@@ -566,6 +661,14 @@ mod tests {
566
661
}
567
662
568
663
fn is_nan ( self ) -> bool ;
664
+
665
+ fn checked_add ( self , rhs : Self ) -> Option < Self > ;
666
+ fn checked_div ( self , rhs : Self ) -> Option < Self > ;
667
+ fn checked_mul ( self , rhs : Self ) -> Option < Self > ;
668
+ fn checked_rem ( self , rhs : Self ) -> Option < Self > ;
669
+ fn checked_sub ( self , rhs : Self ) -> Option < Self > ;
670
+ fn checked_shl ( self , rhs : Self ) -> Option < Self > ;
671
+ fn checked_shr ( self , rhs : Self ) -> Option < Self > ;
569
672
}
570
673
571
674
trait ByteArray :
@@ -618,7 +721,7 @@ mod tests {
618
721
}
619
722
620
723
macro_rules! impl_traits {
621
- ( $name: ident, $native: ident, $bytes: expr, $sign: ident $( , $is_nan : ident) ?) => {
724
+ ( $name: ident, $native: ident, $bytes: expr, $sign: ident $( , @$float : ident) ?) => {
622
725
impl Native for $native {
623
726
// For some types, `0 as $native` is required (for example, when
624
727
// `$native` is a floating-point type; `0` is an integer), but
@@ -631,9 +734,7 @@ mod tests {
631
734
type Distribution = Standard ;
632
735
const DIST : Standard = Standard ;
633
736
634
- fn is_nan( self ) -> bool {
635
- false $( || self . $is_nan( ) ) ?
636
- }
737
+ impl_traits!( @float_dependent_methods $( @$float) ?) ;
637
738
}
638
739
639
740
impl <O : ByteOrder > ByteOrderType for $name<O > {
@@ -665,6 +766,26 @@ mod tests {
665
766
666
767
impl_byte_order_type_unsigned!( $name, $sign) ;
667
768
} ;
769
+ ( @float_dependent_methods) => {
770
+ fn is_nan( self ) -> bool { false }
771
+ fn checked_add( self , rhs: Self ) -> Option <Self > { self . checked_add( rhs) }
772
+ fn checked_div( self , rhs: Self ) -> Option <Self > { self . checked_div( rhs) }
773
+ fn checked_mul( self , rhs: Self ) -> Option <Self > { self . checked_mul( rhs) }
774
+ fn checked_rem( self , rhs: Self ) -> Option <Self > { self . checked_rem( rhs) }
775
+ fn checked_sub( self , rhs: Self ) -> Option <Self > { self . checked_sub( rhs) }
776
+ fn checked_shl( self , rhs: Self ) -> Option <Self > { self . checked_shl( rhs. try_into( ) . unwrap_or( u32 :: MAX ) ) }
777
+ fn checked_shr( self , rhs: Self ) -> Option <Self > { self . checked_shr( rhs. try_into( ) . unwrap_or( u32 :: MAX ) ) }
778
+ } ;
779
+ ( @float_dependent_methods @float) => {
780
+ fn is_nan( self ) -> bool { self . is_nan( ) }
781
+ fn checked_add( self , rhs: Self ) -> Option <Self > { Some ( self + rhs) }
782
+ fn checked_div( self , rhs: Self ) -> Option <Self > { Some ( self / rhs) }
783
+ fn checked_mul( self , rhs: Self ) -> Option <Self > { Some ( self * rhs) }
784
+ fn checked_rem( self , rhs: Self ) -> Option <Self > { Some ( self % rhs) }
785
+ fn checked_sub( self , rhs: Self ) -> Option <Self > { Some ( self - rhs) }
786
+ fn checked_shl( self , _rhs: Self ) -> Option <Self > { unimplemented!( ) }
787
+ fn checked_shr( self , _rhs: Self ) -> Option <Self > { unimplemented!( ) }
788
+ } ;
668
789
}
669
790
670
791
impl_traits ! ( U16 , u16 , 2 , unsigned) ;
@@ -675,30 +796,39 @@ mod tests {
675
796
impl_traits ! ( I32 , i32 , 4 , signed) ;
676
797
impl_traits ! ( I64 , i64 , 8 , signed) ;
677
798
impl_traits ! ( I128 , i128 , 16 , signed) ;
678
- impl_traits ! ( F32 , f32 , 4 , signed, is_nan ) ;
679
- impl_traits ! ( F64 , f64 , 8 , signed, is_nan ) ;
799
+ impl_traits ! ( F32 , f32 , 4 , signed, @float ) ;
800
+ impl_traits ! ( F64 , f64 , 8 , signed, @float ) ;
680
801
681
- macro_rules! call_for_all_types {
802
+ macro_rules! call_for_unsigned_types {
682
803
( $fn: ident, $byteorder: ident) => {
683
804
$fn:: <U16 <$byteorder>>( ) ;
684
805
$fn:: <U32 <$byteorder>>( ) ;
685
806
$fn:: <U64 <$byteorder>>( ) ;
686
807
$fn:: <U128 <$byteorder>>( ) ;
808
+ } ;
809
+ }
810
+
811
+ macro_rules! call_for_signed_types {
812
+ ( $fn: ident, $byteorder: ident) => {
687
813
$fn:: <I16 <$byteorder>>( ) ;
688
814
$fn:: <I32 <$byteorder>>( ) ;
689
815
$fn:: <I64 <$byteorder>>( ) ;
690
816
$fn:: <I128 <$byteorder>>( ) ;
817
+ } ;
818
+ }
819
+
820
+ macro_rules! call_for_float_types {
821
+ ( $fn: ident, $byteorder: ident) => {
691
822
$fn:: <F32 <$byteorder>>( ) ;
692
823
$fn:: <F64 <$byteorder>>( ) ;
693
824
} ;
694
825
}
695
826
696
- macro_rules! call_for_unsigned_types {
827
+ macro_rules! call_for_all_types {
697
828
( $fn: ident, $byteorder: ident) => {
698
- $fn:: <U16 <$byteorder>>( ) ;
699
- $fn:: <U32 <$byteorder>>( ) ;
700
- $fn:: <U64 <$byteorder>>( ) ;
701
- $fn:: <U128 <$byteorder>>( ) ;
829
+ call_for_unsigned_types!( $fn, $byteorder) ;
830
+ call_for_signed_types!( $fn, $byteorder) ;
831
+ call_for_float_types!( $fn, $byteorder) ;
702
832
} ;
703
833
}
704
834
@@ -834,6 +964,114 @@ mod tests {
834
964
call_for_all_types ! ( test_non_native_endian, NonNativeEndian ) ;
835
965
}
836
966
967
+ #[ cfg_attr( test, test) ]
968
+ fn test_ops_impls ( ) {
969
+ // Test implementations of traits in `core::ops`. Some of these are
970
+ // fairly banal, but some are optimized to perform the operation without
971
+ // swapping byte order (namely, bit-wise operations which are identical
972
+ // regardless of byte order). These are important to test, and while
973
+ // we're testing those anyway, it's trivial to test all of the impls.
974
+
975
+ fn test < T , F , G , H > ( op : F , op_native : G , op_native_checked : Option < H > )
976
+ where
977
+ T : ByteOrderType ,
978
+ F : Fn ( T , T ) -> T ,
979
+ G : Fn ( T :: Native , T :: Native ) -> T :: Native ,
980
+ H : Fn ( T :: Native , T :: Native ) -> Option < T :: Native > ,
981
+ {
982
+ let mut r = SmallRng :: seed_from_u64 ( RNG_SEED ) ;
983
+ for _ in 0 ..RAND_ITERS {
984
+ let n0 = T :: Native :: rand ( & mut r) ;
985
+ let n1 = T :: Native :: rand ( & mut r) ;
986
+ let t0 = T :: new ( n0) ;
987
+ let t1 = T :: new ( n1) ;
988
+
989
+ // If this operation would overflow/underflow, skip it rather
990
+ // than attempt to catch and recover from panics.
991
+ if matches ! ( & op_native_checked, Some ( checked) if checked( n0, n1) . is_none( ) ) {
992
+ continue ;
993
+ }
994
+
995
+ let n_res = op_native ( n0, n1) ;
996
+ let t_res = op ( t0, t1) ;
997
+
998
+ // For `f32` and `f64`, NaN values are not considered equal to
999
+ // themselves. We store `Option<f32>`/`Option<f64>` and store
1000
+ // NaN as `None` so they can still be compared.
1001
+ let n_res = ( !T :: Native :: is_nan ( n_res) ) . then ( || n_res) ;
1002
+ let t_res = ( !T :: Native :: is_nan ( t_res. get ( ) ) ) . then ( || t_res. get ( ) ) ;
1003
+ assert_eq ! ( n_res, t_res) ;
1004
+ }
1005
+ }
1006
+
1007
+ macro_rules! test {
1008
+ ( @binary $trait: ident, $method: ident $( [ $checked_method: ident] ) ?, $( $call_for_macros: ident) ,* ) => { {
1009
+ test!(
1010
+ @inner $trait,
1011
+ core:: ops:: $trait:: $method,
1012
+ core:: ops:: $trait:: $method,
1013
+ {
1014
+ #[ allow( unused_mut, unused_assignments) ]
1015
+ let mut op_native_checked = None :: <fn ( T :: Native , T :: Native ) -> Option <T :: Native >>;
1016
+ $(
1017
+ op_native_checked = Some ( T :: Native :: $checked_method) ;
1018
+ ) ?
1019
+ op_native_checked
1020
+ } ,
1021
+ $( $call_for_macros) ,*
1022
+ ) ;
1023
+ } } ;
1024
+ ( @unary $trait: ident, $method: ident $( [ $checked_method: ident] ) ?, $( $call_for_macros: ident) ,* ) => { {
1025
+ test!(
1026
+ @inner $trait,
1027
+ |slf, _rhs| core:: ops:: $trait:: $method( slf) ,
1028
+ |slf, _rhs| core:: ops:: $trait:: $method( slf) ,
1029
+ {
1030
+ #[ allow( unused_mut, unused_assignments) ]
1031
+ let mut op_native_checked = None :: <fn ( T :: Native , T :: Native ) -> Option <T :: Native >>;
1032
+ $(
1033
+ op_native_checked = Some ( |slf, _rhs| T :: Native :: $checked_method( slf) ) ;
1034
+ ) ?
1035
+ op_native_checked
1036
+ } ,
1037
+ $( $call_for_macros) ,*
1038
+ ) ;
1039
+ } } ;
1040
+ ( @inner $trait: ident, $op: expr, $op_native: expr, $op_native_checked: expr, $( $call_for_macros: ident) ,* ) => { {
1041
+ fn t<T : ByteOrderType + core:: ops:: $trait<Output = T >>( )
1042
+ where
1043
+ T :: Native : core:: ops:: $trait<Output = T :: Native >,
1044
+ {
1045
+ test:: <T , _, _, _>(
1046
+ $op,
1047
+ $op_native,
1048
+ $op_native_checked,
1049
+ ) ;
1050
+ }
1051
+
1052
+ $(
1053
+ $call_for_macros!( t, NativeEndian ) ;
1054
+ $call_for_macros!( t, NonNativeEndian ) ;
1055
+ ) *
1056
+ } } ;
1057
+ }
1058
+
1059
+ test ! ( @binary Add , add[ checked_add] , call_for_all_types) ;
1060
+ test ! ( @binary Div , div[ checked_div] , call_for_all_types) ;
1061
+ test ! ( @binary Mul , mul[ checked_mul] , call_for_all_types) ;
1062
+ test ! ( @binary Rem , rem[ checked_rem] , call_for_all_types) ;
1063
+ test ! ( @binary Sub , sub[ checked_sub] , call_for_all_types) ;
1064
+
1065
+ test ! ( @binary BitAnd , bitand, call_for_unsigned_types, call_for_signed_types) ;
1066
+ test ! ( @binary BitOr , bitor, call_for_unsigned_types, call_for_signed_types) ;
1067
+ test ! ( @binary BitXor , bitxor, call_for_unsigned_types, call_for_signed_types) ;
1068
+ test ! ( @binary Shl , shl[ checked_shl] , call_for_unsigned_types, call_for_signed_types) ;
1069
+ test ! ( @binary Shr , shr[ checked_shr] , call_for_unsigned_types, call_for_signed_types) ;
1070
+
1071
+ test ! ( @unary Not , not, call_for_signed_types, call_for_unsigned_types) ;
1072
+ test ! ( @unary Neg , neg, call_for_signed_types, call_for_float_types) ;
1073
+ }
1074
+
837
1075
#[ test]
838
1076
fn test_debug_impl ( ) {
839
1077
// Ensure that Debug applies format options to the inner value.
0 commit comments