mod control;
mod converter;
mod numeric;
mod struct_reg;
mod swissknife;
mod symbolic;
pub use control::{parse_category, parse_category_empty, parse_command, parse_command_empty};
pub use converter::{parse_converter, parse_int_converter, parse_string};
pub use numeric::{parse_float, parse_integer};
pub use struct_reg::parse_struct_reg;
pub use swissknife::parse_swissknife;
pub use symbolic::{parse_boolean, parse_enum};
use quick_xml::Reader;
use quick_xml::events::BytesStart;
use crate::builders::AddressingBuilder;
use crate::util::{attribute_value, parse_u64, read_text_start};
use crate::{NodeMeta, PredicateRefs, Representation, Visibility, XmlError};
pub const TAG_P_ADDRESS: &[u8] = b"pAddress";
pub const TAG_VALUE: &[u8] = b"Value";
pub const TAG_P_VALUE: &[u8] = b"pValue";
pub const TAG_DISPLAY_NAME: &[u8] = b"DisplayName";
pub const TAG_VISIBILITY: &[u8] = b"Visibility";
pub const TAG_DESCRIPTION: &[u8] = b"Description";
pub const TAG_TOOLTIP: &[u8] = b"ToolTip";
pub const TAG_REPRESENTATION: &[u8] = b"Representation";
pub const TAG_LSB: &[u8] = b"Lsb";
pub const TAG_MSB: &[u8] = b"Msb";
pub const TAG_BIT: &[u8] = b"Bit";
pub const TAG_MASK: &[u8] = b"Mask";
pub const TAG_ENDIANNESS: &[u8] = b"Endianness";
pub const TAG_ENDIANESS: &[u8] = b"Endianess";
pub const TAG_BYTE_ORDER: &[u8] = b"ByteOrder";
pub const TAG_P_IS_IMPLEMENTED: &[u8] = b"pIsImplemented";
pub const TAG_P_IS_AVAILABLE: &[u8] = b"pIsAvailable";
pub const TAG_P_IS_LOCKED: &[u8] = b"pIsLocked";
pub fn handle_predicate_start(
reader: &mut Reader<&[u8]>,
event: &BytesStart<'_>,
prefs: &mut PredicateRefs,
) -> Result<bool, XmlError> {
let slot: &mut Option<String> = match event.name().as_ref() {
TAG_P_IS_IMPLEMENTED => &mut prefs.p_is_implemented,
TAG_P_IS_AVAILABLE => &mut prefs.p_is_available,
TAG_P_IS_LOCKED => &mut prefs.p_is_locked,
_ => return Ok(false),
};
let text = read_text_start(reader, event)?;
let trimmed = text.trim();
if !trimmed.is_empty() {
*slot = Some(trimmed.to_string());
}
Ok(true)
}
#[derive(Debug, Default)]
pub struct SelectorState {
pub selectors: Vec<String>,
pub selected_if: Vec<(String, Vec<String>)>,
pub last_selector: Option<usize>,
}
impl SelectorState {
pub fn into_parts(self) -> (Vec<String>, Vec<(String, Vec<String>)>) {
(self.selectors, self.selected_if)
}
}
pub fn handle_p_selected_start(
reader: &mut Reader<&[u8]>,
event: &BytesStart<'_>,
addressing: &mut AddressingBuilder,
state: &mut SelectorState,
) -> Result<(), XmlError> {
let text = read_text_start(reader, event)?;
let selector = text.trim().to_string();
if !selector.is_empty() {
state.selectors.push(selector.clone());
state.selected_if.push((selector.clone(), Vec::new()));
state.last_selector = Some(state.selected_if.len() - 1);
addressing.register_selector(&selector);
}
Ok(())
}
pub fn handle_selected_start(
reader: &mut Reader<&[u8]>,
event: &BytesStart<'_>,
name: &str,
addressing: &mut AddressingBuilder,
state: &mut SelectorState,
) -> Result<(), XmlError> {
let mut value = attribute_value(event, b"Value")?;
if value.is_none() {
value = attribute_value(event, b"Name")?;
}
let text = read_text_start(reader, event)?;
let trimmed = text.trim();
if value.is_none() && !trimmed.is_empty() {
value = Some(trimmed.to_string());
}
if let Some(val) = value.clone() {
addressing.push_selected_value(val.clone());
if let Some(address_attr) = attribute_value(event, b"Address")? {
let len_override = attribute_value(event, b"Length")?
.map(|len| -> Result<u32, XmlError> {
let parsed = parse_u64(&len)?;
u32::try_from(parsed).map_err(|_| {
XmlError::Invalid(format!("length out of range for node {name}"))
})
})
.transpose()?;
addressing.attach_selected_address(parse_u64(&address_attr)?, len_override);
} else if let Some(len_attr) = attribute_value(event, b"Length")? {
let parsed = parse_u64(&len_attr)?;
let len = u32::try_from(parsed)
.map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
addressing.apply_length(len);
}
}
if let Some(idx) = state.last_selector {
if let Some(value) = value {
let trimmed = value.trim();
if !trimmed.is_empty() {
state.selected_if[idx].1.push(trimmed.to_string());
}
} else if !trimmed.is_empty() {
state.selected_if[idx].1.push(trimmed.to_string());
}
}
Ok(())
}
pub fn handle_p_selected_empty(
event: &BytesStart<'_>,
addressing: &mut AddressingBuilder,
state: &mut SelectorState,
) -> Result<(), XmlError> {
if let Some(value) = attribute_value(event, b"Name")? {
addressing.register_selector(&value);
state.selectors.push(value.clone());
state.selected_if.push((value, Vec::new()));
state.last_selector = Some(state.selected_if.len() - 1);
}
Ok(())
}
pub fn handle_selected_empty(
event: &BytesStart<'_>,
name: &str,
addressing: &mut AddressingBuilder,
state: &mut SelectorState,
) -> Result<(), XmlError> {
if let Some(val) = attribute_value(event, b"Value")? {
addressing.push_selected_value(val.clone());
if let Some(address_attr) = attribute_value(event, b"Address")? {
let len_override = attribute_value(event, b"Length")?
.map(|len| -> Result<u32, XmlError> {
let parsed = parse_u64(&len)?;
u32::try_from(parsed).map_err(|_| {
XmlError::Invalid(format!("length out of range for node {name}"))
})
})
.transpose()?;
addressing.attach_selected_address(parse_u64(&address_attr)?, len_override);
} else if let Some(len_attr) = attribute_value(event, b"Length")? {
let parsed = parse_u64(&len_attr)?;
let len = u32::try_from(parsed)
.map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
addressing.apply_length(len);
}
if let Some(idx) = state.last_selector {
state.selected_if[idx].1.push(val);
}
}
Ok(())
}
pub fn handle_addressing_start(
reader: &mut Reader<&[u8]>,
event: &BytesStart<'_>,
name: &str,
addressing: &mut AddressingBuilder,
) -> Result<bool, XmlError> {
match event.name().as_ref() {
b"Address" => {
let text = read_text_start(reader, event)?;
addressing.attach_selected_address(parse_u64(&text)?, None);
Ok(true)
}
TAG_P_ADDRESS => {
let text = read_text_start(reader, event)?;
let target = text.trim();
if !target.is_empty() {
addressing.set_p_address_node(target);
}
Ok(true)
}
b"Length" => {
let text = read_text_start(reader, event)?;
let value = parse_u64(&text)?;
let len = u32::try_from(value)
.map_err(|_| XmlError::Invalid(format!("length out of range for node {name}")))?;
addressing.apply_length(len);
Ok(true)
}
_ => Ok(false),
}
}
#[derive(Debug, Default)]
pub struct NodeMetaBuilder {
pub visibility: Option<Visibility>,
pub description: Option<String>,
pub tooltip: Option<String>,
pub display_name: Option<String>,
pub representation: Option<Representation>,
}
impl NodeMetaBuilder {
pub fn handle_start(
&mut self,
reader: &mut Reader<&[u8]>,
event: &BytesStart<'_>,
) -> Result<bool, XmlError> {
match event.name().as_ref() {
TAG_VISIBILITY => {
let text = read_text_start(reader, event)?;
self.visibility = Visibility::parse(&text);
Ok(true)
}
TAG_DESCRIPTION => {
let text = read_text_start(reader, event)?;
let trimmed = text.trim();
if !trimmed.is_empty() {
self.description = Some(trimmed.to_string());
}
Ok(true)
}
TAG_TOOLTIP => {
let text = read_text_start(reader, event)?;
let trimmed = text.trim();
if !trimmed.is_empty() {
self.tooltip = Some(trimmed.to_string());
}
Ok(true)
}
TAG_DISPLAY_NAME => {
let text = read_text_start(reader, event)?;
let trimmed = text.trim();
if !trimmed.is_empty() {
self.display_name = Some(trimmed.to_string());
}
Ok(true)
}
TAG_REPRESENTATION => {
let text = read_text_start(reader, event)?;
self.representation = Representation::parse(&text);
Ok(true)
}
_ => Ok(false),
}
}
pub fn build(self) -> NodeMeta {
NodeMeta {
visibility: self.visibility.unwrap_or_default(),
description: self.description,
tooltip: self.tooltip,
display_name: self.display_name,
representation: self.representation,
}
}
}
pub fn handle_addressing_empty(
event: &BytesStart<'_>,
addressing: &mut AddressingBuilder,
) -> Result<bool, XmlError> {
match event.name().as_ref() {
TAG_P_ADDRESS => {
if let Some(value) = attribute_value(event, b"Name")? {
let trimmed = value.trim();
if !trimmed.is_empty() {
addressing.set_p_address_node(trimmed);
}
}
Ok(true)
}
_ => Ok(false),
}
}