use std::cell::Cell;
use std::rc::Rc;
use roxmltree::Node;
use crate::base::instruction::Instruction;
use crate::{Error, Result};
pub(crate) struct Template {
pub(crate) id: u32,
pub(crate) name: String,
pub(crate) type_ref: TypeRef,
pub(crate) dictionary: Dictionary,
pub(crate) instructions: Vec<Instruction>,
pub(crate) require_pmap: Cell<Option<bool>>,
}
impl Template {
pub(crate) fn from_node(node: Node) -> Result<Self> {
if node.tag_name().name() != "template" {
return Err(Error::Static(format!(
"expected <template/> node, got <{}/>",
node.tag_name().name()
)));
}
let id = node.attribute("id").unwrap_or("0").parse::<u32>()?;
let name = node
.attribute("name")
.ok_or_else(|| Error::Static("template name not found".to_string()))?
.to_string();
let type_ref = node
.attribute("typeRef")
.map_or(TypeRef::Any, TypeRef::from_str);
let dictionary = node
.attribute("dictionary")
.map_or(Dictionary::Global, Dictionary::from_str);
let mut instructions = Vec::new();
for child in node.children() {
if child.is_element() {
instructions.push(Instruction::from_node(child)?);
}
}
Ok(Self {
id,
name,
type_ref,
dictionary,
instructions,
require_pmap: Cell::new(None),
})
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub(crate) enum Operator {
None,
Constant,
Default,
Copy,
Increment,
Delta,
Tail,
}
impl Operator {
pub(crate) fn new_from_tag(t: &str) -> Result<Self> {
match t {
"constant" => Ok(Self::Constant),
"default" => Ok(Self::Default),
"copy" => Ok(Self::Copy),
"increment" => Ok(Self::Increment),
"delta" => Ok(Self::Delta),
"tail" => Ok(Self::Tail),
_ => Err(Error::Static(format!("Unknown operator: {t}"))),
}
}
}
#[derive(Debug, PartialEq, Copy, Clone)]
pub(crate) enum Presence {
Mandatory,
Optional,
}
impl Presence {
pub(crate) fn from_str(s: &str) -> Result<Self> {
match s {
"mandatory" => Ok(Self::Mandatory),
"optional" => Ok(Self::Optional),
_ => Err(Error::Static(format!("unknown presence: {s}"))),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum Dictionary {
Inherit,
Global,
Template,
Type,
UserDefined(Rc<str>),
}
impl Dictionary {
pub(crate) fn from_str(name: &str) -> Self {
match name {
"global" => Self::Global,
"template" => Self::Template,
"type" => Self::Type,
_ => Self::UserDefined(Rc::from(name)),
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub(crate) enum TypeRef {
Any,
ApplicationType(Rc<str>),
}
impl TypeRef {
pub(crate) fn from_str(name: &str) -> Self {
Self::ApplicationType(Rc::from(name))
}
}