use quick_xml::Reader;
use quick_xml::events::{BytesStart, Event};
use crate::util::{attribute_value_required, parse_u64, read_text_start, skip_element};
use crate::{
AccessMode, Addressing, BitField, ByteOrder, NodeDecl, NodeMeta, PredicateRefs, XmlError,
};
pub fn parse_struct_reg(
reader: &mut Reader<&[u8]>,
start: BytesStart<'_>,
) -> Result<Vec<NodeDecl>, XmlError> {
let mut address: Option<u64> = None;
let mut length: u32 = 4;
let mut access = AccessMode::RW;
let mut byte_order = ByteOrder::Little;
let mut entries = Vec::new();
let node_name = start.name().as_ref().to_vec();
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => match e.name().as_ref() {
b"Address" => {
let text = read_text_start(reader, e)?;
address = Some(parse_u64(&text)?);
}
b"Length" => {
let text = read_text_start(reader, e)?;
length = parse_u64(&text)? as u32;
}
b"AccessMode" => {
let text = read_text_start(reader, e)?;
access = AccessMode::parse(&text)?;
}
b"Endianness" | b"Endianess" => {
let text = read_text_start(reader, e)?;
if let Some(order) = ByteOrder::parse(&text) {
byte_order = order;
}
}
b"StructEntry" => {
let entry = parse_struct_entry(reader, e.clone(), byte_order)?;
entries.push(entry);
}
_ => skip_element(reader, e.name().as_ref())?,
},
Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
Ok(Event::Eof) => {
return Err(XmlError::Invalid("unterminated StructReg".into()));
}
Err(err) => return Err(XmlError::Xml(err.to_string())),
_ => {}
}
buf.clear();
}
let addr = address.unwrap_or(0);
let addressing = Addressing::Fixed {
address: addr,
len: length,
};
let nodes = entries
.into_iter()
.map(|entry| NodeDecl::Integer {
name: entry.name,
meta: NodeMeta::default(),
addressing: Some(addressing.clone()),
len: length,
access,
min: i64::MIN,
max: i64::MAX,
inc: None,
unit: None,
bitfield: Some(entry.bitfield),
selectors: Vec::new(),
selected_if: Vec::new(),
pvalue: None,
p_max: None,
p_min: None,
value: None,
predicates: PredicateRefs::default(),
})
.collect();
Ok(nodes)
}
struct StructEntryData {
name: String,
bitfield: BitField,
}
fn parse_struct_entry(
reader: &mut Reader<&[u8]>,
start: BytesStart<'_>,
default_byte_order: ByteOrder,
) -> Result<StructEntryData, XmlError> {
let name = attribute_value_required(&start, b"Name")?;
let mut lsb: Option<u16> = None;
let mut msb: Option<u16> = None;
let mut bit: Option<u16> = None;
let node_name = start.name().as_ref().to_vec();
let mut buf = Vec::new();
loop {
match reader.read_event_into(&mut buf) {
Ok(Event::Start(ref e)) => match e.name().as_ref() {
b"LSB" => {
let text = read_text_start(reader, e)?;
lsb = Some(parse_u64(&text)? as u16);
}
b"MSB" => {
let text = read_text_start(reader, e)?;
msb = Some(parse_u64(&text)? as u16);
}
b"Bit" => {
let text = read_text_start(reader, e)?;
bit = Some(parse_u64(&text)? as u16);
}
_ => skip_element(reader, e.name().as_ref())?,
},
Ok(Event::End(ref e)) if e.name().as_ref() == node_name.as_slice() => break,
Ok(Event::Eof) => {
return Err(XmlError::Invalid(format!(
"unterminated StructEntry {name}"
)));
}
Err(err) => return Err(XmlError::Xml(err.to_string())),
_ => {}
}
buf.clear();
}
let bitfield = if let Some(single) = bit {
BitField {
bit_offset: single,
bit_length: 1,
byte_order: default_byte_order,
}
} else if let (Some(l), Some(m)) = (lsb, msb) {
let (low, high) = if l <= m { (l, m) } else { (m, l) };
BitField {
bit_offset: low,
bit_length: high - low + 1,
byte_order: default_byte_order,
}
} else {
return Err(XmlError::Invalid(format!(
"StructEntry {name} needs LSB+MSB or Bit"
)));
};
Ok(StructEntryData { name, bitfield })
}