27
27
#![ deny( clippy:: arithmetic_side_effects) ]
28
28
29
29
use anyhow:: { anyhow, ensure, Context , Result } ;
30
- use can_dbc:: { Message , MultiplexIndicator , Signal , ValDescription , ValueDescription , DBC } ;
30
+ use can_dbc:: ValueType :: Signed ;
31
+ use can_dbc:: {
32
+ Message , MultiplexIndicator , Signal , ValDescription , ValueDescription , ValueType , DBC ,
33
+ } ;
31
34
use heck:: { ToPascalCase , ToSnakeCase } ;
32
35
use pad:: PadAdapter ;
36
+ use std:: cmp:: { max, min} ;
33
37
use std:: {
34
38
collections:: { BTreeMap , BTreeSet } ,
35
39
fmt:: Display ,
40
+ i128, i64,
36
41
io:: { self , BufWriter , Write } ,
37
42
} ;
38
- use std:: cmp:: max;
39
43
use typed_builder:: TypedBuilder ;
40
44
41
-
42
45
mod includes;
43
46
mod keywords;
44
47
mod pad;
@@ -1035,11 +1038,6 @@ fn write_enum(
1035
1038
///
1036
1039
/// NOTE: Factor and offset must be whole integers.
1037
1040
fn scaled_signal_to_rust_int ( signal : & Signal ) -> String {
1038
- let sign = match signal. value_type ( ) {
1039
- can_dbc:: ValueType :: Signed => "i" ,
1040
- can_dbc:: ValueType :: Unsigned => "u" ,
1041
- } ;
1042
-
1043
1041
assert ! (
1044
1042
signal. factor. fract( ) . abs( ) <= f64 :: EPSILON ,
1045
1043
"Signal Factor ({}) should be an integer" ,
@@ -1052,49 +1050,120 @@ fn scaled_signal_to_rust_int(signal: &Signal) -> String {
1052
1050
) ;
1053
1051
1054
1052
// calculate the maximum possible signal value, accounting for factor and offset
1053
+ signal_params_to_rust_int (
1054
+ * signal. value_type ( ) ,
1055
+ signal. signal_size as u32 ,
1056
+ signal. factor as i64 ,
1057
+ signal. offset as i64 ,
1058
+ )
1059
+ . expect ( & format ! (
1060
+ "Signal {} could not be represented as a Rust integer" ,
1061
+ & signal. name( )
1062
+ ) )
1063
+ }
1064
+
1065
+ fn signal_params_to_rust_int (
1066
+ sign : ValueType ,
1067
+ signal_size : u32 ,
1068
+ factor : i64 ,
1069
+ offset : i64 ,
1070
+ ) -> Option < String > {
1071
+ if signal_size > 64 {
1072
+ return None ;
1073
+ }
1074
+ let range = get_range_of_values ( sign, signal_size, factor, offset) ;
1075
+ match range {
1076
+ Some ( ( low, high) ) => Some ( range_to_rust_int ( low, high) ) ,
1077
+ _ => None ,
1078
+ }
1079
+ }
1080
+
1081
+ /// Using the signal's parameters, find the range of values that it spans
1082
+ fn get_range_of_values (
1083
+ sign : ValueType ,
1084
+ signal_size : u32 ,
1085
+ factor : i64 ,
1086
+ offset : i64 ,
1087
+ ) -> Option < ( i128 , i128 ) > {
1088
+ let range1;
1089
+ let range2;
1090
+ match sign {
1091
+ Signed => {
1092
+ range1 = 1i128
1093
+ . checked_shl ( signal_size - 1 )
1094
+ . and_then ( |n| n. checked_mul ( -1 ) )
1095
+ . and_then ( |n| n. checked_mul ( factor. into ( ) ) )
1096
+ . and_then ( |n| n. checked_add ( offset. into ( ) ) ) ;
1097
+ range2 = 1i128
1098
+ . checked_shl ( signal_size - 1 )
1099
+ . and_then ( |n| n. checked_sub ( 1 ) )
1100
+ . and_then ( |n| n. checked_mul ( factor. into ( ) ) )
1101
+ . and_then ( |n| n. checked_add ( offset. into ( ) ) ) ;
1102
+ }
1103
+ ValueType :: Unsigned => {
1104
+ range1 = Some ( 0 ) ;
1105
+ range2 = 1i128
1106
+ . checked_shl ( signal_size)
1107
+ . and_then ( |n| n. checked_sub ( 1 ) )
1108
+ . and_then ( |n| n. checked_mul ( factor. into ( ) ) )
1109
+ . and_then ( |n| n. checked_add ( offset. into ( ) ) ) ;
1110
+ }
1111
+ }
1112
+ match ( range1, range2) {
1113
+ ( Some ( a) , Some ( b) ) => Some ( ( min ( a, b) , max ( a, b) ) ) ,
1114
+ _ => None ,
1115
+ }
1116
+ }
1117
+
1118
+ fn apply_factor_and_offset ( input : Option < i64 > , factor : i64 , offset : i64 ) -> Option < i64 > {
1119
+ input
1120
+ . and_then ( |n| n. checked_mul ( factor) )
1121
+ . and_then ( |n| n. checked_add ( offset) )
1122
+ }
1055
1123
1056
- if signal. min >= 0.0 {
1057
- let factor = signal. factor as u64 ;
1058
- let offset = signal. offset as u64 ;
1059
- let max_value = 1u64
1060
- . checked_shl ( * signal. signal_size ( ) as u32 )
1061
- . map ( |n| n. saturating_sub ( 1 ) )
1062
- . and_then ( |n| n. checked_mul ( factor) )
1063
- . and_then ( |n| n. checked_add ( offset) )
1064
- . unwrap_or ( u64:: MAX ) ;
1065
-
1066
- let size = match max_value {
1067
- n if n <= u8:: MAX . into ( ) => "8" ,
1068
- n if n <= u16:: MAX . into ( ) => "16" ,
1069
- n if n <= u32:: MAX . into ( ) => "32" ,
1070
- _ => "64" ,
1124
+ /// Determine the smallest Rust integer type that can fit the range of values
1125
+ /// Only values derived from 64 bit integers are supported, i.e. the range [-2^64-1, 2^64-1]
1126
+ fn range_to_rust_int ( low : i128 , high : i128 ) -> String {
1127
+ // Two cases:
1128
+ // Min is negative, in which case lower and upper bounds are signed
1129
+ // Min is positive so lower/upper bounds are unsigned
1130
+ let lower_bound: u8 ;
1131
+ let upper_bound: u8 ;
1132
+ let sign: & str ;
1133
+
1134
+ if low < 0 {
1135
+ // signed case
1136
+ sign = "i" ;
1137
+ lower_bound = match low {
1138
+ n if n >= i8:: MIN . into ( ) => 8 ,
1139
+ n if n >= i16:: MIN . into ( ) => 16 ,
1140
+ n if n >= i32:: MIN . into ( ) => 32 ,
1141
+ n if n >= i64:: MIN . into ( ) => 64 ,
1142
+ _ => 128 ,
1143
+ } ;
1144
+ upper_bound = match high {
1145
+ n if n <= i8:: MAX . into ( ) => 8 ,
1146
+ n if n <= i16:: MAX . into ( ) => 16 ,
1147
+ n if n <= i32:: MAX . into ( ) => 32 ,
1148
+ n if n <= i64:: MAX . into ( ) => 64 ,
1149
+ _ => 128 ,
1071
1150
} ;
1072
- format ! ( "{sign}{size}" )
1073
1151
} else {
1074
- let factor = signal. factor as i64 ;
1075
- let offset = signal. offset as i64 ;
1076
- let max_value = 1i64
1077
- . checked_shl ( * signal. signal_size ( ) as u32 )
1078
- . map ( |n| n. saturating_sub ( 1 ) )
1079
- . and_then ( |n| n. checked_mul ( factor) )
1080
- . and_then ( |n| n. checked_add ( offset) )
1081
- . unwrap_or ( i64:: MAX ) ;
1082
-
1083
- let size = match max_value {
1084
- n if n <= i8:: MAX . into ( ) => "8" ,
1085
- n if n <= i16:: MAX . into ( ) => "16" ,
1086
- n if n <= i32:: MAX . into ( ) => "32" ,
1087
- _ => "64" ,
1152
+ sign = "u" ;
1153
+ lower_bound = 8 ;
1154
+ upper_bound = match high {
1155
+ n if n <= u8:: MAX . into ( ) => 8 ,
1156
+ n if n <= u16:: MAX . into ( ) => 16 ,
1157
+ n if n <= u32:: MAX . into ( ) => 32 ,
1158
+ n if n <= u64:: MAX . into ( ) => 64 ,
1159
+ _ => 128 ,
1088
1160
} ;
1089
- format ! ( "i{size}" )
1090
1161
}
1091
- }
1092
1162
1093
- fn signal_params_to_rust_int ( signal_size : u32 , factor : i64 , offset : i64 ) -> String {
1094
- String :: from ( "u8 ")
1163
+ let size = max ( lower_bound , upper_bound ) ;
1164
+ format ! ( "{sign}{size} ")
1095
1165
}
1096
1166
1097
-
1098
1167
/// Determine the smallest rust integer that can fit the raw signal values.
1099
1168
fn signal_to_rust_int ( signal : & Signal ) -> String {
1100
1169
let sign = match signal. value_type ( ) {
@@ -1124,7 +1193,6 @@ fn signal_to_rust_uint(signal: &Signal) -> String {
1124
1193
format ! ( "u{}" , size)
1125
1194
}
1126
1195
1127
-
1128
1196
#[ allow( clippy:: float_cmp) ]
1129
1197
fn signal_is_float_in_rust ( signal : & Signal ) -> bool {
1130
1198
signal. offset . fract ( ) != 0.0 || signal. factor . fract ( ) != 0.0
@@ -1518,19 +1586,43 @@ impl FeatureConfig<'_> {
1518
1586
1519
1587
#[ cfg( test) ]
1520
1588
mod tests {
1521
- use crate :: signal_params_to_rust_int;
1589
+ use crate :: { get_range_of_values, range_to_rust_int, signal_params_to_rust_int} ;
1590
+ use can_dbc:: ValueType :: { Signed , Unsigned } ;
1522
1591
1523
1592
#[ test]
1524
- fn test_something ( ) {
1525
- // TODO drop
1526
- assert_eq ! ( 1 , 1 ) ;
1593
+ fn test_range_of_values ( ) {
1594
+ assert_eq ! ( get_range_of_values( Unsigned , 4 , 1 , 0 ) , Some ( ( 0 , 15 ) ) ) ;
1595
+ assert_eq ! (
1596
+ get_range_of_values( Unsigned , 32 , -1 , 0 ) ,
1597
+ Some ( ( -( u32 :: MAX as i128 ) , 0 ) )
1598
+ ) ;
1527
1599
}
1528
1600
1529
1601
#[ test]
1530
- fn test_convert_signal_params_to_rust_int ( ) {
1531
- assert_eq ! ( signal_params_to_rust_int( 8 , 1 , 0 ) , "u8" ) ;
1532
- assert_eq ! ( signal_params_to_rust_int( 8 , 2 , 0 ) , "u16" ) ;
1533
-
1602
+ fn test_range_to_rust_int ( ) {
1603
+ assert_eq ! ( range_to_rust_int( 0 , 255 ) , "u8" ) ;
1604
+ assert_eq ! ( range_to_rust_int( -1 , 127 ) , "i8" ) ;
1605
+ assert_eq ! ( range_to_rust_int( -1 , 128 ) , "i16" ) ;
1606
+ assert_eq ! ( range_to_rust_int( -1 , 255 ) , "i16" ) ;
1607
+ assert_eq ! ( range_to_rust_int( -65535 , 0 ) , "i32" ) ;
1608
+ assert_eq ! ( range_to_rust_int( -129 , -127 ) , "i16" ) ;
1609
+ assert_eq ! ( range_to_rust_int( 0 , 1i128 << 65 ) , "u128" ) ;
1610
+ assert_eq ! ( range_to_rust_int( -( 1i128 << 65 ) , 0 ) , "i128" ) ;
1534
1611
}
1535
1612
1613
+ #[ test]
1614
+ fn test_convert_signal_params_to_rust_int ( ) {
1615
+ assert_eq ! ( signal_params_to_rust_int( Signed , 8 , 1 , 0 ) . unwrap( ) , "i8" ) ;
1616
+ assert_eq ! ( signal_params_to_rust_int( Signed , 8 , 2 , 0 ) . unwrap( ) , "i16" ) ;
1617
+ assert_eq ! ( signal_params_to_rust_int( Signed , 63 , 1 , 0 ) . unwrap( ) , "i64" ) ;
1618
+ assert_eq ! (
1619
+ signal_params_to_rust_int( Unsigned , 64 , -1 , 0 ) . unwrap( ) ,
1620
+ "i128"
1621
+ ) ;
1622
+ assert_eq ! (
1623
+ signal_params_to_rust_int( Unsigned , 65 , 1 , 0 ) ,
1624
+ None ,
1625
+ "This shouldn't be valid in a DBC, it's more than 64 bits"
1626
+ ) ;
1627
+ }
1536
1628
}
0 commit comments