Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 52 additions & 4 deletions src/ast/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ mod tests {
use super::*;
use crate::ast::{ByteOrder, MultiplexIndicator, ValueType};
use crate::test_helpers::*;
use crate::NumericValue;

#[test]
fn message_definition_test() {
Expand All @@ -80,8 +81,8 @@ BO_ 1 MCA_A1: 6 MFA
value_type: ValueType::Unsigned,
factor: 1.0,
offset: 0.0,
min: 0.0,
max: 0.0,
min: NumericValue::Uint(0),
max: NumericValue::Uint(0),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["XYZ_OUS".to_string()],
Expand All @@ -94,8 +95,55 @@ BO_ 1 MCA_A1: 6 MFA
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: 0.0,
max: 0.0,
min: NumericValue::Uint(0),
max: NumericValue::Uint(0),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["DFA_FUS".to_string()],
},
],
};
let val = test_into::<Message>(def.trim_start(), Rule::message);
assert_eq!(val, exp);
}

#[test]
fn min_max_numeric_test() {
let def = r#"BO_ 1 MCA_A1: 6 MFA
SG_ uint : 9|2@1+ (1,0) [0|18446744073709551615] "x" XYZ_OUS
SG_ int : 3|2@0- (1,0) [-9223372036854775808|9223372036854775807] "x" DFA_FUS
"#;

let exp = Message {
id: MessageId::Standard(1),
name: "MCA_A1".to_string(),
size: 6,
transmitter: Transmitter::NodeName("MFA".to_string()),
signals: vec![
Signal {
name: "uint".to_string(),
start_bit: 9,
size: 2,
byte_order: ByteOrder::LittleEndian,
value_type: ValueType::Unsigned,
factor: 1.0,
offset: 0.0,
min: NumericValue::Uint(0),
max: NumericValue::Uint(18_446_744_073_709_551_615),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["XYZ_OUS".to_string()],
},
Signal {
name: "int".to_string(),
start_bit: 3,
size: 2,
byte_order: ByteOrder::BigEndian,
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: NumericValue::Int(-9_223_372_036_854_775_808),
max: NumericValue::Uint(9_223_372_036_854_775_807),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["DFA_FUS".to_string()],
Expand Down
41 changes: 40 additions & 1 deletion src/ast/numeric_value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::str::FromStr;

use crate::DbcError;

#[derive(Clone, Debug, PartialEq)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum NumericValue {
Uint(u64),
Expand All @@ -25,3 +25,42 @@ impl FromStr for NumericValue {
}
}
}

impl std::fmt::Display for NumericValue {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
NumericValue::Uint(v) => write!(f, "{v}"),
NumericValue::Int(v) => write!(f, "{v}"),
NumericValue::Double(v) => write!(f, "{v}"),
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn unsigned_max() {
let value = u64::MAX.to_string();
assert_eq!(
format!("{}", NumericValue::from_str(&value).unwrap()),
value
);
}

#[test]
fn signed_min() {
let value = i64::MIN.to_string();
assert_eq!(
format!("{}", NumericValue::from_str(&value).unwrap()),
value
);
}

#[test]
fn double() {
let value = "3.141592653589793";
assert_eq!(format!("{}", NumericValue::from_str(value).unwrap()), value);
}
}
18 changes: 9 additions & 9 deletions src/ast/signal.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use can_dbc_pest::{Pair, Rule};

use crate::ast::{ByteOrder, MultiplexIndicator, ValueType};
use crate::ast::{ByteOrder, MultiplexIndicator, NumericValue, ValueType};
use crate::parser::{
collect_strings, next, next_optional_rule, next_rule, next_string, parse_min_max_float,
collect_strings, next, next_optional_rule, next_rule, next_string, parse_min_max_numeric,
parse_next_float, parse_next_inner_str, parse_next_uint, validated_inner,
};
use crate::DbcError;
Expand All @@ -21,8 +21,8 @@ pub struct Signal {
pub value_type: ValueType,
pub factor: f64,
pub offset: f64,
pub min: f64,
pub max: f64,
pub min: NumericValue,
pub max: NumericValue,
pub unit: String,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub receivers: Vec<String>,
Expand All @@ -49,7 +49,7 @@ impl TryFrom<Pair<'_, Rule>> for Signal {
let value_type = next(&mut pairs)?.try_into()?;
let factor = parse_next_float(&mut pairs, Rule::factor)?;
let offset = parse_next_float(&mut pairs, Rule::offset)?;
let (min, max) = parse_min_max_float(next_rule(&mut pairs, Rule::min_max)?)?;
let (min, max) = parse_min_max_numeric(next_rule(&mut pairs, Rule::min_max)?)?;
let unit = parse_next_inner_str(&mut pairs, Rule::unit)?;
let receivers = collect_strings(&mut pairs, Rule::node_name)?;

Expand Down Expand Up @@ -89,8 +89,8 @@ mod tests {
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: 0.0,
max: 0.0,
min: NumericValue::Uint(0),
max: NumericValue::Uint(0),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["UFA".to_string()],
Expand All @@ -112,8 +112,8 @@ mod tests {
value_type: ValueType::Signed,
factor: 1.0,
offset: 0.0,
min: 0.0,
max: 0.0,
min: NumericValue::Uint(0),
max: NumericValue::Uint(0),
unit: "x".to_string(),
multiplexer_indicator: MultiplexIndicator::Plain,
receivers: vec!["DFA_FUS".to_string()],
Expand Down
15 changes: 11 additions & 4 deletions src/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

use can_dbc_pest::{Error as PestError, Pair, Pairs, Rule};

use crate::ast::NumericValue;

pub type DbcResult<T> = Result<T, DbcError>;

/// A helper function to decode cp1252 bytes, as DBC files are often encoded in cp1252.
Expand Down Expand Up @@ -232,12 +234,17 @@ pub(crate) fn parse_min_max_int(pair: Pair<Rule>) -> DbcResult<(i64, i64)> {
Ok((min_val, max_val))
}

/// Helper to parse min/max values from a `min_max` rule as floats
pub(crate) fn parse_min_max_float(pair: Pair<Rule>) -> DbcResult<(f64, f64)> {
/// Helper to parse min/max values from a `min_max` rule as `NumericValue`
/// This preserves the exact value without precision loss for large integers like 2**64
pub(crate) fn parse_min_max_numeric(pair: Pair<Rule>) -> DbcResult<(NumericValue, NumericValue)> {
let mut pairs = pair.into_inner();

let min_val = parse_next_float(&mut pairs, Rule::minimum)?;
let max_val = parse_next_float(&mut pairs, Rule::maximum)?;
let min_val = next_rule(&mut pairs, Rule::minimum)?
.as_str()
.parse::<NumericValue>()?;
let max_val = next_rule(&mut pairs, Rule::maximum)?
.as_str()
.parse::<NumericValue>()?;
expect_empty(&pairs).expect("pest grammar ensures no extra items");

Ok((min_val, max_val))
Expand Down
30 changes: 20 additions & 10 deletions tests/snapshots/canpy/DBC_template.snap
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,10 @@ messages:
value_type: Unsigned
factor: 1
offset: 0
min: 0
max: 0
min:
Uint: 0
max:
Uint: 0
unit: ""
receivers:
- Node1
Expand All @@ -86,8 +88,10 @@ messages:
value_type: Unsigned
factor: 1
offset: 0
min: 0
max: 0
min:
Uint: 0
max:
Uint: 0
unit: ""
receivers:
- Node0
Expand All @@ -99,8 +103,10 @@ messages:
value_type: Unsigned
factor: 1
offset: 0
min: 0
max: 0
min:
Uint: 0
max:
Uint: 0
unit: ""
receivers:
- Node0
Expand All @@ -119,8 +125,10 @@ messages:
value_type: Unsigned
factor: 100
offset: 0
min: 0
max: 100
min:
Uint: 0
max:
Uint: 100
unit: "%"
receivers:
- Node1
Expand All @@ -133,8 +141,10 @@ messages:
value_type: Signed
factor: 1
offset: 0
min: 0
max: 0
min:
Uint: 0
max:
Uint: 0
unit: ""
receivers:
- Node1
Expand Down
6 changes: 4 additions & 2 deletions tests/snapshots/dbc-cantools/BU_BO_REL_.snap
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ messages:
value_type: Unsigned
factor: 1
offset: 0
min: 0
max: 100
min:
Uint: 0
max:
Uint: 100
unit: "%"
receivers:
- Vector__XXX
Expand Down
6 changes: 4 additions & 2 deletions tests/snapshots/dbc-cantools/BU_BO_REL_Message.snap
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,10 @@ messages:
value_type: Unsigned
factor: 1
offset: 0
min: 0
max: 100
min:
Uint: 0
max:
Uint: 100
unit: ""
receivers:
- ECU2
Expand Down
Loading