use std::{collections::HashMap, sync::Arc};
use crate::{document::InterpretedValue, parser::AttributeValue};
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct ResolvedAttributes {
attribute_values: Arc<HashMap<String, AttributeValue>>,
default_attribute_values: Arc<HashMap<String, String>>,
counter_values: HashMap<String, String>,
}
impl ResolvedAttributes {
pub(crate) fn new(
attribute_values: Arc<HashMap<String, AttributeValue>>,
default_attribute_values: Arc<HashMap<String, String>>,
counter_values: HashMap<String, String>,
) -> Self {
Self {
attribute_values,
default_attribute_values,
counter_values,
}
}
pub(crate) fn attribute_value<N: AsRef<str>>(&self, name: N) -> InterpretedValue {
if let Some(value) = self.counter_values.get(name.as_ref()) {
return InterpretedValue::Value(value.clone());
}
self.attribute_values
.get(name.as_ref())
.map(|av| av.value.clone())
.map(|av| {
if let InterpretedValue::Set = av
&& let Some(default) = self.default_attribute_values.get(name.as_ref())
{
InterpretedValue::Value(default.clone())
} else {
av
}
})
.unwrap_or(InterpretedValue::Unset)
}
pub(crate) fn has_attribute<N: AsRef<str>>(&self, name: N) -> bool {
self.counter_values.contains_key(name.as_ref())
|| self.attribute_values.contains_key(name.as_ref())
}
pub(crate) fn is_attribute_set<N: AsRef<str>>(&self, name: N) -> bool {
if self.counter_values.contains_key(name.as_ref()) {
return true;
}
self.attribute_values
.get(name.as_ref())
.map(|a| a.value != InterpretedValue::Unset)
.unwrap_or(false)
}
}
#[cfg(test)]
mod tests {
use std::{collections::HashMap, sync::Arc};
use crate::{
document::InterpretedValue,
parser::{AllowableValue, AttributeValue, ModificationContext, ResolvedAttributes},
};
fn attr(value: InterpretedValue) -> AttributeValue {
AttributeValue {
allowable_value: AllowableValue::Any,
modification_context: ModificationContext::Anywhere,
value,
}
}
fn sample() -> ResolvedAttributes {
let mut attribute_values: HashMap<String, AttributeValue> = HashMap::new();
attribute_values.insert(
"value".to_string(),
attr(InterpretedValue::Value("v".to_string())),
);
attribute_values.insert("set-with-default".to_string(), attr(InterpretedValue::Set));
attribute_values.insert("set-no-default".to_string(), attr(InterpretedValue::Set));
attribute_values.insert("unset".to_string(), attr(InterpretedValue::Unset));
attribute_values.insert(
"shadowed".to_string(),
attr(InterpretedValue::Value("attr".to_string())),
);
let mut default_attribute_values: HashMap<String, String> = HashMap::new();
default_attribute_values.insert("set-with-default".to_string(), "d".to_string());
let mut counter_values: HashMap<String, String> = HashMap::new();
counter_values.insert("count".to_string(), "3".to_string());
counter_values.insert("shadowed".to_string(), "counter".to_string());
ResolvedAttributes::new(
Arc::new(attribute_values),
Arc::new(default_attribute_values),
counter_values,
)
}
#[test]
fn attribute_value_resolves_each_shape() {
let attrs = sample();
assert_eq!(
attrs.attribute_value("value"),
InterpretedValue::Value("v".to_string())
);
assert_eq!(
attrs.attribute_value("set-with-default"),
InterpretedValue::Value("d".to_string())
);
assert_eq!(
attrs.attribute_value("set-no-default"),
InterpretedValue::Set
);
assert_eq!(attrs.attribute_value("unset"), InterpretedValue::Unset);
assert_eq!(attrs.attribute_value("absent"), InterpretedValue::Unset);
assert_eq!(
attrs.attribute_value("count"),
InterpretedValue::Value("3".to_string())
);
assert_eq!(
attrs.attribute_value("shadowed"),
InterpretedValue::Value("counter".to_string())
);
}
#[test]
fn has_attribute_reports_presence() {
let attrs = sample();
assert!(attrs.has_attribute("value"));
assert!(attrs.has_attribute("unset"));
assert!(attrs.has_attribute("count"));
assert!(!attrs.has_attribute("absent"));
}
#[test]
fn is_attribute_set_reports_set_state() {
let attrs = sample();
assert!(attrs.is_attribute_set("value"));
assert!(attrs.is_attribute_set("set-no-default"));
assert!(!attrs.is_attribute_set("unset"));
assert!(!attrs.is_attribute_set("absent"));
assert!(attrs.is_attribute_set("count"));
}
}