use std::{collections::HashMap, sync::Arc};
use crate::{
document::InterpretedValue,
parser::{
AttributeValue,
built_in_attrs::{built_in_attr, synthesized_attr},
},
};
#[derive(Clone, Debug, Default, 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 {
let name = name.as_ref();
if let Some(value) = self.counter_values.get(name) {
return InterpretedValue::Value(value.clone());
}
match self.effective_attribute(name) {
Some(av) => {
if let InterpretedValue::Set = av.value
&& let Some(default) = self.default_attribute_values.get(name)
{
InterpretedValue::Value(default.clone())
} else {
av.value.clone()
}
}
None => InterpretedValue::Unset,
}
}
fn effective_attribute(&self, name: &str) -> Option<&AttributeValue> {
if let Some(av) = self.attribute_values.get(name) {
return Some(av);
}
if let Some(av) = built_in_attr(name) {
return Some(av);
}
synthesized_attr(name, &self.attribute_values)
}
pub(crate) fn has_attribute<N: AsRef<str>>(&self, name: N) -> bool {
let name = name.as_ref();
self.counter_values.contains_key(name) || self.effective_attribute(name).is_some()
}
pub(crate) fn is_attribute_set<N: AsRef<str>>(&self, name: N) -> bool {
let name = name.as_ref();
if self.counter_values.contains_key(name) {
return true;
}
self.effective_attribute(name)
.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,
silent_when_locked: false,
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"));
}
}