use std::{
collections::HashMap,
fmt::{self, format, Display},
};
pub type Props<'a> = HashMap<&'a str, &'a str>;
pub type Modifier = fn(item: Item) -> Item;
#[derive(Debug, Clone)]
pub struct Item<'a> {
pub name: &'a str,
pub props: Option<Props<'a>>,
}
impl<'a> Display for Item<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let props = self.props.clone().unwrap_or_default();
let props: Vec<String> = props
.iter()
.map(|(key, value)| format(format_args!("{}={}", key, value)))
.collect::<_>();
write!(f, "{}{{{}}}", self.name, props.join(","))
}
}
impl<'a> Item<'a> {
pub fn a(name: &'a str) -> Self {
Self { name, props: None }
}
pub fn an(name: &'a str) -> Self {
Item::a(name)
}
pub fn named(name: &'a str) -> Self {
Item::a(name)
}
pub fn from(name: &'a str, props: Props<'a>) -> Self {
Item {
name,
props: Some(props),
}
}
pub fn extend(&self, name: &'a str, ext_props: Props<'a>) -> Self {
let mut new_props: HashMap<&str, &str> = HashMap::new();
new_props.extend(self.props.clone().unwrap_or_default().iter());
new_props.extend(ext_props.iter());
Item {
name,
props: Some(new_props),
}
}
pub fn has_prop(&self, key: &str) -> bool {
match &self.props {
None => false,
Some(props) => props.contains_key(key),
}
}
pub fn get_prop(&self, key: &str) -> Option<&str> {
match &self.props {
None => None,
Some(props) => props.get(key).copied(),
}
}
pub fn set_prop<'b: 'a>(&mut self, key: &'b str, value: &'b str) -> &mut Self {
let mut new_props: HashMap<&str, &str> = HashMap::new();
new_props.extend(self.props.clone().unwrap_or_default().iter());
new_props.insert(key, value);
self.props = Some(new_props);
self
}
}