use std::str;
use can_dbc_pest::{DbcParser, Parser as _, Rule};
use crate::ast::{
AttributeDefault, AttributeDefinition, AttributeValueForObject, Baudrate, Comment,
EnvironmentVariable, EnvironmentVariableData, ExtendedMultiplex, Message, MessageId,
MessageTransmitter, MultiplexIndicator, Node, Signal, SignalExtendedValueType,
SignalExtendedValueTypeList, SignalGroups, SignalType, SignalTypeRef, Symbol, ValDescription,
ValueDescription, ValueTable, Version,
};
use crate::parser::{collect_all, DbcError, DbcResult};
use crate::{AttributeValue, AttributeValueForObjectType, AttributeValueForRelation};
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Dbc {
pub version: Version,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub new_symbols: Vec<Symbol>,
pub bit_timing: Option<Vec<Baudrate>>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub nodes: Vec<Node>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub value_tables: Vec<ValueTable>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub messages: Vec<Message>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub message_transmitters: Vec<MessageTransmitter>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub environment_variables: Vec<EnvironmentVariable>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub environment_variable_data: Vec<EnvironmentVariableData>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub signal_types: Vec<SignalType>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub comments: Vec<Comment>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_definitions: Vec<AttributeDefinition>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub relation_attribute_definitions: Vec<AttributeDefinition>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_defaults: Vec<AttributeDefault>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub relation_attribute_defaults: Vec<AttributeDefault>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub relation_attribute_values: Vec<AttributeValueForRelation>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_values_database: Vec<AttributeValueForDatabase>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_values_node: Vec<AttributeValueForNode>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_values_message: Vec<AttributeValueForMessage>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_values_signal: Vec<AttributeValueForSignal>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub attribute_values_env: Vec<AttributeValueForEnvVariable>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub value_descriptions: Vec<ValueDescription>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub signal_type_refs: Vec<SignalTypeRef>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub signal_groups: Vec<SignalGroups>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub signal_extended_value_type_list: Vec<SignalExtendedValueTypeList>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))]
pub extended_multiplex: Vec<ExtendedMultiplex>,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForDatabase {
pub name: String,
pub value: AttributeValue,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForNode {
pub name: String,
pub node_name: String,
pub value: AttributeValue,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForMessage {
pub name: String,
pub message_id: MessageId,
pub value: AttributeValue,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForSignal {
pub name: String,
pub message_id: MessageId,
pub signal_name: String,
pub value: AttributeValue,
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForEnvVariable {
pub name: String,
pub variable_name: String,
pub value: AttributeValue,
}
impl Dbc {
#[must_use]
pub fn signal_by_name(&self, message_id: MessageId, signal_name: &str) -> Option<&Signal> {
let message = self
.messages
.iter()
.find(|message| message.id == message_id);
if let Some(message) = message {
return message
.signals
.iter()
.find(|signal| signal.name == *signal_name);
}
None
}
#[must_use]
pub fn message_comment(&self, message_id: MessageId) -> Option<&str> {
self.comments.iter().find_map(|x| match x {
Comment::Message {
id: ref x_message_id,
ref comment,
} => {
if *x_message_id == message_id {
Some(comment.as_str())
} else {
None
}
}
_ => None,
})
}
#[must_use]
pub fn signal_comment(&self, message_id: MessageId, signal_name: &str) -> Option<&str> {
self.comments.iter().find_map(|x| match x {
Comment::Signal {
message_id: ref x_message_id,
name: ref x_signal_name,
comment,
} => {
if *x_message_id == message_id && x_signal_name == signal_name {
Some(comment.as_str())
} else {
None
}
}
_ => None,
})
}
#[must_use]
pub fn value_descriptions_for_signal(
&self,
message_id: MessageId,
signal_name: &str,
) -> Option<&[ValDescription]> {
self.value_descriptions.iter().find_map(|x| match x {
ValueDescription::Signal {
message_id: ref x_message_id,
name: ref x_signal_name,
ref value_descriptions,
} => {
if *x_message_id == message_id && x_signal_name == signal_name {
Some(value_descriptions.as_slice())
} else {
None
}
}
ValueDescription::EnvironmentVariable { .. } => None,
})
}
#[must_use]
pub fn extended_value_type_for_signal(
&self,
message_id: MessageId,
signal_name: &str,
) -> Option<&SignalExtendedValueType> {
self.signal_extended_value_type_list.iter().find_map(|x| {
let SignalExtendedValueTypeList {
message_id: ref x_message_id,
signal_name: ref x_signal_name,
ref signal_extended_value_type,
} = x;
if *x_message_id == message_id && x_signal_name == signal_name {
Some(signal_extended_value_type)
} else {
None
}
})
}
pub fn message_multiplexor_switch(&self, message_id: MessageId) -> DbcResult<Option<&Signal>> {
let message = self
.messages
.iter()
.find(|message| message.id == message_id);
if let Some(message) = message {
if self
.extended_multiplex
.iter()
.any(|ext_mp| ext_mp.message_id == message_id)
{
Err(DbcError::MultipleMultiplexors)
} else {
Ok(message
.signals
.iter()
.find(|signal| signal.multiplexer_indicator == MultiplexIndicator::Multiplexor))
}
} else {
Ok(None)
}
}
}
impl<'a> TryFrom<&'a str> for Dbc {
type Error = DbcError;
fn try_from(dbc_in: &'a str) -> Result<Self, Self::Error> {
dbc(dbc_in)
}
}
#[allow(clippy::too_many_lines)] pub(crate) fn dbc(buffer: &str) -> DbcResult<Dbc> {
let mut version = Version::default();
let mut new_symbols = vec![];
let mut bit_timing = None;
let mut nodes = vec![];
let mut value_tables = vec![];
let mut messages: Vec<Message> = vec![];
let mut message_transmitters = vec![];
let mut environment_variables = vec![];
let mut environment_variable_data = vec![];
let mut comments = vec![];
let mut attribute_definitions = vec![];
let mut relation_attribute_definitions = vec![];
let mut attribute_defaults = vec![];
let mut relation_attribute_defaults = vec![];
let mut attribute_values_database = vec![];
let mut attribute_values_node = vec![];
let mut attribute_values_message = vec![];
let mut attribute_values_signal = vec![];
let mut attribute_values_env = vec![];
let mut relation_attribute_values = vec![];
let mut value_descriptions = vec![];
let mut signal_groups = vec![];
let mut signal_extended_value_type_list = vec![];
let mut extended_multiplex = vec![];
for pair in DbcParser::parse(Rule::file, buffer)? {
if !matches!(pair.as_rule(), Rule::file) {
return Err(DbcError::ExpectedRule(Rule::file, pair.as_rule()));
}
for pairs in pair.into_inner() {
match pairs.as_rule() {
Rule::version => version = pairs.try_into()?,
Rule::new_symbols => {
let symbols: Vec<Symbol> = collect_all::<Symbol>(&mut pairs.into_inner())?;
new_symbols.extend(symbols);
}
Rule::bit_timing => {
let _inner_pairs = pairs.into_inner();
bit_timing = Some(vec![]);
}
Rule::nodes => nodes = collect_all::<Node>(&mut pairs.into_inner())?,
Rule::message => messages.push(pairs.try_into()?),
Rule::comment => comments.push(pairs.try_into()?),
Rule::attr_def => attribute_definitions.push(pairs.try_into()?),
Rule::ba_def_rel => relation_attribute_definitions.push(pairs.try_into()?),
Rule::ba_rel => relation_attribute_values.push(pairs.try_into()?),
Rule::attr_value => {
let attr_value: AttributeValueForObject = pairs.try_into()?;
match attr_value.value {
AttributeValueForObjectType::Raw(attribute_value) => {
attribute_values_database.push(AttributeValueForDatabase {
name: attr_value.name,
value: attribute_value,
});
}
AttributeValueForObjectType::NetworkNode(node_name, attribute_value) => {
attribute_values_node.push(AttributeValueForNode {
name: attr_value.name,
node_name,
value: attribute_value,
});
}
AttributeValueForObjectType::MessageDefinition(
message_id,
attribute_value,
) => {
if let Some(value) = attribute_value {
attribute_values_message.push(AttributeValueForMessage {
name: attr_value.name,
message_id,
value,
});
}
}
AttributeValueForObjectType::Signal(
message_id,
signal_name,
attribute_value,
) => {
attribute_values_signal.push(AttributeValueForSignal {
name: attr_value.name,
message_id,
signal_name,
value: attribute_value,
});
}
AttributeValueForObjectType::EnvVariable(
variable_name,
attribute_value,
) => {
attribute_values_env.push(AttributeValueForEnvVariable {
name: attr_value.name,
variable_name,
value: attribute_value,
});
}
}
}
Rule::value_table => value_tables.push(pairs.try_into()?),
Rule::value_table_def => value_descriptions.push(pairs.try_into()?),
Rule::signal_group => signal_groups.push(pairs.try_into()?),
Rule::signal_value_type => {
signal_extended_value_type_list.push(pairs.try_into()?);
}
Rule::message_transmitter => message_transmitters.push(pairs.try_into()?),
Rule::ba_def_def => attribute_defaults.push(pairs.try_into()?),
Rule::ba_def_def_rel => relation_attribute_defaults.push(pairs.try_into()?),
Rule::sg_mul_val => extended_multiplex.push(pairs.try_into()?),
Rule::environment_variable => {
environment_variables.push(pairs.try_into()?);
}
Rule::env_var_data => environment_variable_data.push(pairs.try_into()?),
Rule::EOI => {
}
other => panic!("Unexpected rule in DBC file: {other:?}"),
}
}
}
Ok(Dbc {
version,
new_symbols,
bit_timing,
nodes,
value_tables,
messages,
message_transmitters,
environment_variables,
environment_variable_data,
signal_types: vec![], comments,
attribute_definitions,
relation_attribute_definitions,
attribute_defaults,
relation_attribute_defaults,
relation_attribute_values,
attribute_values_database,
attribute_values_node,
attribute_values_message,
attribute_values_signal,
attribute_values_env,
value_descriptions,
signal_type_refs: vec![], signal_groups,
signal_extended_value_type_list,
extended_multiplex,
})
}