1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
use super::{ExtendedMultiplexing, ValueRanges};
use crate::{Parser, compat::validate_name};
impl ExtendedMultiplexing {
/// Parse an SG_MUL_VAL_ entry
///
/// Expects the parser to be positioned after the SG_MUL_VAL_ keyword.
/// Parses: message_id signal_name multiplexer_switch value_ranges ;
/// Example: 500 Signal_A Mux1 0-5,10-15 ;
///
/// Returns `None` if parsing fails (caller should skip to end of line).
pub(crate) fn parse(parser: &mut Parser) -> Option<ExtendedMultiplexing> {
parser.skip_newlines_and_spaces();
// Parse message_id
let message_id = parser.parse_u32().ok()?;
parser.skip_newlines_and_spaces();
// Parse signal_name
let signal_name_str = parser.parse_identifier().ok()?;
let signal_name = validate_name(signal_name_str).ok()?;
parser.skip_newlines_and_spaces();
// Parse multiplexer_switch
let multiplexer_switch_str = parser.parse_identifier().ok()?;
let multiplexer_switch = validate_name(multiplexer_switch_str).ok()?;
parser.skip_newlines_and_spaces();
// Parse value ranges
let mut value_ranges: ValueRanges = ValueRanges::new();
// Parse value ranges (at least one required)
loop {
parser.skip_newlines_and_spaces();
// Parse value range: min-max
// We need to manually parse numbers because parse_u32() stops at whitespace/colon/pipe/@,
// but not at "-", which causes it to error when it encounters "-" after the number.
// We'll parse digits manually until we hit "-", whitespace, comma, or semicolon.
let mut min_value = 0u32;
let mut found_min_digits = false;
loop {
if parser.eof() {
break;
}
let Some(byte) = parser.current_byte() else {
break;
};
if byte.is_ascii_digit() {
found_min_digits = true;
min_value = min_value
.checked_mul(10)
.and_then(|v| v.checked_add((byte - b'0') as u32))?;
parser.advance_one();
} else if parser.matches_any(b" \t-,;") || parser.at_newline() {
// Stop at whitespace, -, comma, or semicolon
break;
} else {
// Invalid character - stop parsing
break;
}
}
if !found_min_digits {
break;
}
let min = min_value as u64;
parser.skip_newlines_and_spaces();
if parser.expect(b"-").is_err() {
break;
}
parser.skip_newlines_and_spaces();
// Parse max value similarly
let mut max_value = 0u32;
let mut found_max_digits = false;
loop {
if parser.eof() {
break;
}
let Some(byte) = parser.current_byte() else {
break;
};
if byte.is_ascii_digit() {
found_max_digits = true;
max_value = max_value
.checked_mul(10)
.and_then(|v| v.checked_add((byte - b'0') as u32))?;
parser.advance_one();
} else if parser.matches_any(b" \t-,;") || parser.at_newline() {
// Stop at whitespace, -, comma, or semicolon
break;
} else {
// Invalid character - stop parsing
break;
}
}
if !found_max_digits {
break;
}
let max = max_value as u64;
if value_ranges.push((min, max)).is_err() {
// Vector full, stop parsing
break;
}
// Check for comma (more ranges) or semicolon (end)
parser.skip_newlines_and_spaces();
if parser.starts_with(b",") {
parser.expect(b",").ok()?;
// Continue to next range
} else if parser.starts_with(b";") {
parser.expect(b";").ok()?;
break;
} else {
// End of ranges (no comma or semicolon)
break;
}
}
// Only return if we parsed at least one range
if value_ranges.is_empty() {
return None;
}
Some(ExtendedMultiplexing::new(
message_id,
signal_name,
multiplexer_switch,
value_ranges,
))
}
}
#[cfg(test)]
mod tests {
use super::ExtendedMultiplexing;
use crate::Parser;
#[test]
fn test_parse_extended_multiplexing_entry() {
let input = b" 500 Signal_A Mux1 5-10 ;";
let mut parser = Parser::new(input).unwrap();
let result = ExtendedMultiplexing::parse(&mut parser);
assert!(
result.is_some(),
"ExtendedMultiplexing::parse should succeed"
);
let ext_mux = result.unwrap();
assert_eq!(ext_mux.message_id(), 500);
assert_eq!(ext_mux.signal_name(), "Signal_A");
assert_eq!(ext_mux.multiplexer_switch(), "Mux1");
assert_eq!(ext_mux.value_ranges(), [(5, 10)]);
}
#[test]
fn test_parse_extended_multiplexing_multiple_ranges() {
let input = b" 500 Signal_B Mux1 0-5,10-15,20-25 ;";
let mut parser = Parser::new(input).unwrap();
let result = ExtendedMultiplexing::parse(&mut parser);
assert!(result.is_some());
let ext_mux = result.unwrap();
assert_eq!(ext_mux.value_ranges(), [(0, 5), (10, 15), (20, 25)]);
}
}