use crate::{error::MuninError, string_table::StringTable};
const NVL_START_INDEX: i32 = 10;
const NULL_INDEX: i32 = 0;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct NameValuePair {
pub key_index: i32,
pub value_index: i32,
}
#[derive(Debug, Default)]
pub struct NameValueListTable {
entries: Vec<Vec<NameValuePair>>,
}
impl NameValueListTable {
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
pub fn add(&mut self, pairs: Vec<NameValuePair>) -> i32 {
let index = NVL_START_INDEX + self.entries.len() as i32;
self.entries.push(pairs);
index
}
pub fn get(&self, index: i32) -> Result<Option<&[NameValuePair]>, MuninError> {
if index == NULL_INDEX {
return Ok(None);
}
let table_index = index - NVL_START_INDEX;
if table_index < 0 || table_index as usize >= self.entries.len() {
return Err(MuninError::InvalidIndex {
kind: "name-value list",
index,
});
}
Ok(Some(&self.entries[table_index as usize]))
}
pub fn resolve(
&self,
index: i32,
strings: &StringTable,
) -> Result<Option<Vec<(String, String)>>, MuninError> {
let pairs = match self.get(index)? {
Some(p) => p,
None => return Ok(None),
};
let mut result = Vec::with_capacity(pairs.len());
for pair in pairs {
let key = match strings.get(pair.key_index)? {
Some(k) => k.to_string(),
None => continue, };
let value = strings.get(pair.value_index)?.unwrap_or("").to_string();
result.push((key, value));
}
Ok(Some(result))
}
pub fn entries(&self) -> &[Vec<NameValuePair>] {
&self.entries
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
#[cfg(test)]
mod tests;