Skip to content
Open
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
13 changes: 11 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ authors = ["marcelbuesing <[email protected]>"]
keywords = ["dbc", "can", "automotive", "ecu"]
categories = ["embedded", "no-std", "encoding", "parsing"]
edition = "2021"
rust-version = "1.74"
rust-version = "1.81"

[[example]]
name = "file_parser"
Expand All @@ -24,9 +24,10 @@ serde = ["dep:serde"]
with-serde = ["serde"]

[dependencies]
can-dbc-pest = { version = "0.6.0" }
encoding_rs = { version = "0.8", optional = true }
nom = { version = "8.0", features = ["alloc"] }
serde = { version = "1.0", features = ["derive"], optional = true }
thiserror = "2.0.17"

[dev-dependencies]
clap = { version = "4.5.0", features = ["cargo", "derive"] }
Expand All @@ -50,3 +51,11 @@ must_use_candidate = "allow" # 12
missing_errors_doc = "allow" # 8
similar_names = "allow" # 4
needless_pass_by_value = "allow" # 4
unnecessary_wraps = "allow"
cast_possible_truncation = "allow"
cast_precision_loss = "allow"
too_many_lines = "allow"
missing_panics_doc = "allow"

#[patch.crates-io]
#can-dbc-pest = { path = "../can-dbc-pest" }
11 changes: 2 additions & 9 deletions examples/file_parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::fs;
use std::str::from_utf8;

use can_dbc::encodings::Encoding;
use can_dbc::{Dbc, Error};
use can_dbc::Dbc;
use clap::Parser;

#[derive(Parser)]
Expand Down Expand Up @@ -36,13 +36,6 @@ fn main() {

match Dbc::try_from(data.as_ref()) {
Ok(dbc_content) => println!("{dbc_content:#?}"),
Err(e) => {
match e {
Error::Nom(nom::Err::Error(e) | nom::Err::Failure(e)) => eprintln!("{e:?}"),
Error::Nom(nom::Err::Incomplete(needed)) => eprintln!("Nom incomplete needed: {needed:#?}"),
Error::Incomplete(dbc, remaining) => eprintln!("Not all data in buffer was read {dbc:#?}, remaining unparsed (length: {}): {remaining}\n...(truncated)", remaining.len()),
Error::MultipleMultiplexors => eprintln!("Multiple multiplexors defined"),
}
}
Err(e) => eprintln!("Error parsing DBC file '{path}': {e}"),
}
}
4 changes: 4 additions & 0 deletions justfile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ export RUST_BACKTRACE := env('RUST_BACKTRACE', if ci_mode == '1' {'1'} else {'0'
bless *args: (cargo-install 'cargo-insta')
cargo insta test --accept --unreferenced=delete {{features}} {{args}}

bless-all: (cargo-install 'cargo-insta')
rm -rf tests/snapshots
FORCE_INSTA=1 {{just_executable()}} bless

# Build the project
build:
cargo build {{packages}} {{features}} {{targets}}
Expand Down
19 changes: 19 additions & 0 deletions src/ast/access_node.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
use can_dbc_pest::{Pair, Rule};

use crate::parser::{validated, DbcError};

// TODO: consider merging with Transmitter

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccessNode {
VectorXXX,
Name(String),
}

impl TryFrom<Pair<'_, Rule>> for AccessNode {
type Error = DbcError;

fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let value = validated(value, Rule::node_name)?.as_str();
Ok(if value == "VECTOR__XXX" {
Self::VectorXXX
} else {
Self::Name(value.to_string())
})
}
}
23 changes: 23 additions & 0 deletions src/ast/access_type.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
use can_dbc_pest::{Pair, Rule};

use crate::parser::{parse_uint, single_inner, validated};
use crate::DbcError;

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AccessType {
Expand All @@ -6,3 +11,21 @@ pub enum AccessType {
DummyNodeVector2,
DummyNodeVector3,
}

impl TryFrom<Pair<'_, Rule>> for AccessType {
type Error = DbcError;

fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let pair = validated(value, Rule::access_type)?;
let value = parse_uint(single_inner(pair, Rule::uint)?)?;

Ok(match value {
0 => Self::DummyNodeVector0,
1 => Self::DummyNodeVector1,
2 => Self::DummyNodeVector2,
3 => Self::DummyNodeVector3,
// FIXME: is this correct?
_ => AccessType::DummyNodeVector0,
})
}
}
16 changes: 16 additions & 0 deletions src/ast/attribute_default.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
use can_dbc_pest::{Pair, Rule};

use crate::ast::AttributeValue;
use crate::parser::{expect_empty, inner_str, next, next_rule, validated_inner, DbcError};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeDefault {
pub name: String,
pub value: AttributeValue,
}

impl TryFrom<Pair<'_, Rule>> for AttributeDefault {
type Error = DbcError;

fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let mut pairs = validated_inner(value, Rule::ba_def_def)?;
let name = inner_str(next_rule(&mut pairs, Rule::attribute_name)?);
let value = next(&mut pairs)?.try_into()?;
expect_empty(&pairs)?;

Ok(Self { name, value })
}
}
44 changes: 44 additions & 0 deletions src/ast/attribute_definition.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use can_dbc_pest::{Pair, Rule};

use crate::parser::{validated_inner, DbcError};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AttributeDefinition {
Expand All @@ -11,3 +15,43 @@ pub enum AttributeDefinition {
// TODO figure out name
Plain(String),
}

impl TryFrom<Pair<'_, Rule>> for AttributeDefinition {
type Error = DbcError;

/// Parse attribute definition: `BA_DEF_ [object_type] attribute_name attribute_type [min max];`
fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let inner_pairs = validated_inner(value, Rule::attr_def)?;
let mut definition_string = String::new();
let mut object_type = "";

// Process all pairs
for pair in inner_pairs {
match pair.as_rule() {
Rule::object_type => {
object_type = pair.as_str();
}
Rule::attribute_name
| Rule::attribute_type_int
| Rule::attribute_type_hex
| Rule::attribute_type_float
| Rule::attribute_type_string
| Rule::attribute_type_enum => {
if !definition_string.is_empty() {
definition_string.push(' ');
}
definition_string.push_str(pair.as_str());
}
v => return Err(DbcError::UnknownRule(v)),
}
}

Ok(match object_type {
"SG_" => Self::Signal(definition_string),
"BO_" => Self::Message(definition_string),
"BU_" => Self::Node(definition_string),
"EV_" => Self::EnvironmentVariable(definition_string),
_ => Self::Plain(definition_string),
})
}
}
17 changes: 17 additions & 0 deletions src/ast/attribute_value.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
use can_dbc_pest::{Pair, Rule};

use crate::parser::{inner_str, parse_float, DbcError};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum AttributeValue {
Expand All @@ -6,3 +10,16 @@ pub enum AttributeValue {
Double(f64),
String(String),
}

impl TryFrom<Pair<'_, Rule>> for AttributeValue {
type Error = DbcError;

fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
match value.as_rule() {
Rule::quoted_str => Ok(Self::String(inner_str(value))),
Rule::number => Ok(Self::Double(parse_float(value)?)),
// FIXME: Add u64 and i64 parsing
_ => Err(Self::Error::ExpectedNumber(value.as_rule())),
}
}
}
17 changes: 17 additions & 0 deletions src/ast/attribute_value_for_object.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,25 @@
use can_dbc_pest::{Pair, Rule};

use crate::ast::AttributeValuedForObjectType;
use crate::parser::{inner_str, next_rule, validated_inner, DbcError};

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct AttributeValueForObject {
pub name: String,
pub value: AttributeValuedForObjectType,
}

impl TryFrom<Pair<'_, Rule>> for AttributeValueForObject {
type Error = DbcError;

/// Parse attribute value: `BA_ attribute_name [object_type] object_name value;`
fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
let mut pairs = validated_inner(value, Rule::attr_value)?;

Ok(Self {
name: inner_str(next_rule(&mut pairs, Rule::attribute_name)?),
value: pairs.try_into()?,
})
}
}
47 changes: 47 additions & 0 deletions src/ast/attribute_valued_for_object_type.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use can_dbc_pest::{Pairs, Rule};

use crate::ast::{AttributeValue, MessageId};
use crate::parser::{expect_empty, next, next_rule, next_string};
use crate::DbcError;

#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
Expand All @@ -9,3 +13,46 @@ pub enum AttributeValuedForObjectType {
Signal(MessageId, String, AttributeValue),
EnvVariable(String, AttributeValue),
}

impl TryFrom<Pairs<'_, Rule>> for AttributeValuedForObjectType {
type Error = DbcError;

fn try_from(mut value: Pairs<Rule>) -> Result<Self, Self::Error> {
// Expect exactly one remaining pair (the object-specific value)
let pair = value.next().ok_or(DbcError::NoMoreRules)?;
if let Some(more) = value.next() {
return Err(DbcError::ExpectedEmpty(more.as_rule()));
}

if matches!(&pair.as_rule(), Rule::quoted_str | Rule::number) {
return Ok(AttributeValuedForObjectType::Raw(pair.try_into()?));
}

let rule = pair.as_rule();
let mut pairs = pair.into_inner();

let res = match rule {
Rule::node_var_val => AttributeValuedForObjectType::NetworkNode(
next_string(&mut pairs, Rule::node_name)?,
next(&mut pairs)?.try_into()?,
),
Rule::msg_var_val => AttributeValuedForObjectType::MessageDefinition(
next_rule(&mut pairs, Rule::message_id)?.try_into()?,
Some(next(&mut pairs)?.try_into()?),
),
Rule::signal_var => AttributeValuedForObjectType::Signal(
next_rule(&mut pairs, Rule::message_id)?.try_into()?,
next_string(&mut pairs, Rule::ident)?,
next(&mut pairs)?.try_into()?,
),
Rule::env_var_val => AttributeValuedForObjectType::EnvVariable(
next_string(&mut pairs, Rule::env_var_name)?,
next(&mut pairs)?.try_into()?,
),
v => return Err(DbcError::UnknownRule(v)),
};

expect_empty(&pairs)?;
Ok(res)
}
}
15 changes: 14 additions & 1 deletion src/ast/baudrate.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
/// Baudrate of network in kbit/s
use can_dbc_pest::{Pair, Rule};

use crate::parser::DbcError;

/// Baudrate of network in KBit/s
#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Baudrate(pub u64);

impl TryFrom<Pair<'_, Rule>> for Baudrate {
type Error = DbcError;

/// Parse bit timing: `BS_: [baud_rate : BTR1 , BTR2 ]`
fn try_from(_value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
todo!("Bit timing parsing not implemented yet");
}
}
16 changes: 16 additions & 0 deletions src/ast/byte_order.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
use can_dbc_pest::{Pair, Rule};

use crate::DbcError;

#[derive(Copy, Clone, Debug, PartialEq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum ByteOrder {
LittleEndian,
BigEndian,
}

impl TryFrom<Pair<'_, Rule>> for ByteOrder {
type Error = DbcError;

fn try_from(value: Pair<'_, Rule>) -> Result<Self, Self::Error> {
match value.as_rule() {
Rule::little_endian => Ok(Self::LittleEndian),
Rule::big_endian => Ok(Self::BigEndian),
v => Err(DbcError::UnknownRule(v)),
}
}
}
Loading