use std::collections::HashMap;
use thiserror::Error;
mod parser;
#[derive(Copy, Clone, Debug, Eq, PartialEq, Error)]
#[error("parsing entry failed at byte {position}: {kind}")]
pub struct ParseError {
pub position: usize,
pub kind: ParseErrorKind,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Error)]
pub enum ParseErrorKind {
#[error("invalid header magic number")]
InvalidHeader,
#[error("unexpected end of file")]
UnexpectedEof,
#[error("name field contains non-ascii characters")]
NonAsciiName,
#[error("user-defined capability has no name name")]
MissingName,
#[error("invalid capability of type {0:?}")]
InvalidField(FieldType),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum FieldType {
Boolean,
Integer,
String
}
pub struct Entry {
pub(crate) names: Vec<String>,
pub(crate) bools: Vec<bool>,
pub(crate) ints: Vec<Option<i32>>,
pub(crate) strs: Vec<Option<Vec<u8>>>,
pub(crate) ext_bools: HashMap<String, bool>,
pub(crate) ext_ints: HashMap<String, Option<i32>>,
pub(crate) ext_strs: HashMap<String, Option<Vec<u8>>>,
}
impl Entry {
pub fn parse(bytes: &[u8]) -> Result<Self, ParseError> {
parser::parse(bytes)
}
pub fn name(&self) -> &str {
&*self.names[0]
}
pub fn aliases(&self) -> impl Iterator<Item = &str> + '_ {
let n = if self.names.len() < 3 {
&[]
} else {
&self.names[1..self.names.len() - 1]
};
n.iter().map(std::ops::Deref::deref)
}
pub fn description(&self) -> Option<&str> {
self.names.last().map(std::ops::Deref::deref)
}
pub fn get_boolean(&self, n: usize) -> bool {
self.bools.get(n).copied().unwrap_or_default()
}
pub fn get_integer(&self, n: usize) -> Option<i32> {
self.ints.get(n).copied().unwrap_or_default()
}
pub fn get_string(&self, n: usize) -> Option<&[u8]> {
self.strs.get(n)?.as_deref()
}
pub fn get_user_boolean(&self, name: &str) -> bool {
self.ext_bools.get(name).copied().unwrap_or_default()
}
pub fn get_user_integer(&self, name: &str) -> Option<i32> {
self.ext_ints.get(name).copied().unwrap_or_default()
}
pub fn get_user_string(&self, name: &str) -> Option<&[u8]> {
self.ext_strs.get(name)?.as_deref()
}
pub fn booleans(&self) -> impl Iterator<Item = bool> + '_ {
self.bools.iter().copied()
}
pub fn integers(&self) -> impl Iterator<Item = Option<i32>> + '_ {
self.ints.iter().copied()
}
pub fn strings(&self) -> impl Iterator<Item = Option<&[u8]>> + '_ {
self.strs.iter().map(Option::as_deref)
}
pub fn user_booleans(&self) -> impl Iterator<Item = (&str, bool)> + '_ {
self.ext_bools.iter().map(|(n, b)| (&**n, *b))
}
pub fn user_integers(&self) -> impl Iterator<Item = (&str, Option<i32>)> + '_ {
self.ext_ints.iter().map(|(n, b)| (&**n, *b))
}
pub fn user_strings(&self) -> impl Iterator<Item = (&str, Option<&[u8]>)> + '_ {
self.ext_strs.iter().map(|(n, b)| (&**n, b.as_deref()))
}
}