use super::{InnerNodes, Node, Nodes};
use crate::{
BU_, Error, MAX_NODES, Parser, Result,
compat::{Name, validate_name},
error::{check_max_limit, map_val_error_with_line},
};
impl Nodes {
#[must_use = "parse result should be checked"]
pub(crate) fn parse(parser: &mut Parser) -> Result<Self> {
let line = parser.line();
parser
.expect(BU_.as_bytes())
.map_err(|_| Error::expected_at("Expected BU_ keyword", line))?;
parser.expect_with_msg(b":", "Expected ':' after BU_")?;
parser.skip_newlines_and_spaces();
let mut nodes: InnerNodes = InnerNodes::new();
let mut node_names: crate::compat::Vec<Name, { MAX_NODES }> = crate::compat::Vec::new();
loop {
parser.skip_whitespace_optional();
match parser.parse_identifier() {
Ok(node) => {
if let Some(err) = check_max_limit(
nodes.len(),
MAX_NODES - 1,
parser.err_nodes(Error::NODES_TOO_MANY),
) {
return Err(err);
}
let node_str = validate_name(node)?;
let _ = node_names.push(node_str.clone());
nodes
.push(Node::new(node_str))
.map_err(|_| parser.err_nodes(Error::NODES_TOO_MANY))?;
}
Err(_) => {
break;
}
}
}
if nodes.is_empty() {
return Ok(Nodes {
nodes: InnerNodes::new(),
});
}
Self::validate(node_names.as_slice()).map_err(|e| {
map_val_error_with_line(
e,
|msg| parser.err_nodes(msg),
|| parser.err_nodes(Error::NODES_ERROR_PREFIX),
)
})?;
Ok(Nodes::new(nodes))
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{Error, Parser};
#[test]
fn test_nodes_from_valid_line() {
let line = b"BU_: ECM TCM BCM ABS";
let mut parser = Parser::new(line).unwrap();
let nodes = Nodes::parse(&mut parser).unwrap();
let mut iter = nodes.iter();
assert_eq!(iter.next(), Some("ECM"));
assert_eq!(iter.next(), Some("TCM"));
assert_eq!(iter.next(), Some("BCM"));
assert_eq!(iter.next(), Some("ABS"));
assert_eq!(iter.next(), None);
}
#[test]
fn test_nodes_from_single_node() {
let line = b"BU_: ONLYONE";
let mut parser = Parser::new(line).unwrap();
let nodes = Nodes::parse(&mut parser).unwrap();
let mut iter = nodes.iter();
assert_eq!(iter.next(), Some("ONLYONE"));
assert_eq!(iter.next(), None);
}
#[test]
fn test_nodes_from_with_extra_spaces() {
let line = b"BU_: Node1 Node2 ";
let mut parser = Parser::new(line).unwrap();
let nodes = Nodes::parse(&mut parser).unwrap();
let mut iter = nodes.iter();
assert_eq!(iter.next(), Some("Node1"));
assert_eq!(iter.next(), Some("Node2"));
assert_eq!(iter.next(), None);
}
#[test]
fn test_nodes_from_empty_list() {
let line = b"BU_:";
let mut parser = Parser::new(line).unwrap();
let nodes = Nodes::parse(&mut parser).unwrap();
assert!(nodes.is_empty());
}
#[test]
fn test_nodes_parse_duplicate() {
let line = b"BU_: ECM TCM ECM";
let mut parser = Parser::new(line).unwrap();
let result = Nodes::parse(&mut parser);
assert!(result.is_err());
match result.unwrap_err() {
Error::Nodes { msg, line } => {
assert_eq!(msg, Error::NODES_DUPLICATE_NAME);
assert_eq!(line, Some(1));
}
_ => panic!("Expected Error::Nodes"),
}
}
}