use std::fmt;
use nom::bytes::complete::tag;
use nom::character::complete::line_ending;
use nom::combinator::map;
use nom::multi::many0;
use nom::{IResult, Parser};
use super::common_parsers::{multispacey, parser_node_name, spacey};
use super::error::DbcParseError;
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct Nodes(pub Vec<String>);
impl fmt::Display for Nodes {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "BU_:",)?;
for node in &self.0 {
write!(f, " {node}")?;
}
writeln!(f)?;
Ok(())
}
}
pub fn parser_nodes(input: &str) -> IResult<&str, Nodes, DbcParseError> {
let res = map(
(
multispacey(tag("BU_")),
spacey(tag(":")),
many0(spacey(parser_node_name)),
many0(line_ending),
),
|(_, _, names, _)| Nodes(names.into_iter().map(String::from).collect()),
)
.parse(input);
match res {
Ok((remain, can_nodes)) => {
log::info!("parse nodes: {:?}", can_nodes.0);
Ok((remain, can_nodes))
}
Err(e) => {
log::trace!("parse nodes failed, e = {e:?}");
Err(nom::Err::Error(DbcParseError::BadCanNodes))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_dbc_can_nodes_01() {
assert_eq!(
parser_nodes(
"BU_: ABS DRS_MM5_10
"
),
Ok(("", Nodes(vec!["ABS".into(), "DRS_MM5_10".into()]))),
);
}
#[test]
fn test_dbc_can_nodes_02() {
assert_eq!(
parser_nodes("BU_:Matrix"),
Ok(("", Nodes(vec!["Matrix".into()]))),
);
}
#[test]
fn test_dbc_can_nodes_03() {
assert_eq!(
parser_nodes("BU_: Node2 Node1 Node0"),
Ok((
"",
Nodes(vec!["Node2".into(), "Node1".into(), "Node0".into()])
)),
);
}
#[test]
fn test_nodes_string_01() {
assert_eq!(
Nodes(vec!["ABS".into(), "DRS_MM5_10".into()]).to_string(),
"BU_: ABS DRS_MM5_10\n",
);
}
#[test]
fn test_nodes_string_02() {
assert_eq!(Nodes(vec![]).to_string(), "BU_:\n",);
}
}