1use std::collections::{hash_map, HashMap};
4
5use fnv::FnvHashSet;
6
7use crate::id::AttrId;
8
9#[derive(Clone, Default)]
11pub struct NamespacePropertyMapping {
12 namespaces: HashMap<String, PropertyMappings>,
13}
14
15#[derive(Clone, Default)]
17pub struct PropertyMappings {
18 properties: HashMap<String, AttributeMappings>,
19}
20
21#[derive(Clone, Default)]
23pub struct AttributeMappings {
24 attributes: HashMap<String, AttrId>,
25}
26
27pub trait NamespacedPropertyAttribute {
29 fn namespace(&self) -> &str;
31
32 fn property(&self) -> &str;
34
35 fn attribute(&self) -> &str;
37}
38
39impl<'a> NamespacedPropertyAttribute for (&'a str, &'a str, &'a str) {
40 fn namespace(&self) -> &str {
41 self.0
42 }
43
44 fn property(&self) -> &str {
45 self.1
46 }
47
48 fn attribute(&self) -> &str {
49 self.2
50 }
51}
52
53impl NamespacePropertyMapping {
54 pub fn namespace_mut(&mut self, namespace_label: String) -> &mut PropertyMappings {
56 self.namespaces.entry(namespace_label).or_default()
57 }
58
59 pub fn attribute_id(&self, attr: &impl NamespacedPropertyAttribute) -> Option<AttrId> {
61 self.namespaces
62 .get(attr.namespace())?
63 .properties
64 .get(attr.property())?
65 .attributes
66 .get(attr.attribute())
67 .cloned()
68 }
69
70 pub fn translate<'a>(
72 &self,
73 attributes: impl IntoIterator<Item = (&'a str, &'a str, &'a str)>,
74 ) -> FnvHashSet<AttrId> {
75 let mut output = FnvHashSet::default();
76 for (namespace, prop, attr) in attributes {
77 let Some(prop_mappings) = self.namespaces.get(namespace) else {
78 continue;
79 };
80 let Some(attr_mappings) = prop_mappings.properties.get(prop) else {
81 continue;
82 };
83 let Some(attr_id) = attr_mappings.attributes.get(attr) else {
84 continue;
85 };
86
87 output.insert(*attr_id);
88 }
89
90 output
91 }
92}
93
94impl PropertyMappings {
95 pub fn property_mut(&mut self, property_label: String) -> &mut AttributeMappings {
97 self.properties.entry(property_label).or_default()
98 }
99}
100
101impl AttributeMappings {
102 pub fn put(&mut self, attribute_label: String, attribute_id: AttrId) {
104 self.attributes
105 .entry(attribute_label)
106 .insert_entry(attribute_id);
107 }
108}
109
110impl IntoIterator for NamespacePropertyMapping {
111 type IntoIter = hash_map::IntoIter<String, PropertyMappings>;
112 type Item = (String, PropertyMappings);
113
114 fn into_iter(self) -> Self::IntoIter {
115 self.namespaces.into_iter()
116 }
117}
118
119impl<'a> IntoIterator for &'a NamespacePropertyMapping {
120 type IntoIter = hash_map::Iter<'a, String, PropertyMappings>;
121 type Item = (&'a String, &'a PropertyMappings);
122
123 fn into_iter(self) -> Self::IntoIter {
124 self.namespaces.iter()
125 }
126}
127
128impl IntoIterator for PropertyMappings {
129 type IntoIter = hash_map::IntoIter<String, AttributeMappings>;
130 type Item = (String, AttributeMappings);
131
132 fn into_iter(self) -> Self::IntoIter {
133 self.properties.into_iter()
134 }
135}
136
137impl<'a> IntoIterator for &'a PropertyMappings {
138 type IntoIter = hash_map::Iter<'a, String, AttributeMappings>;
139 type Item = (&'a String, &'a AttributeMappings);
140
141 fn into_iter(self) -> Self::IntoIter {
142 self.properties.iter()
143 }
144}
145
146impl IntoIterator for AttributeMappings {
147 type IntoIter = hash_map::IntoIter<String, AttrId>;
148 type Item = (String, AttrId);
149
150 fn into_iter(self) -> Self::IntoIter {
151 self.attributes.into_iter()
152 }
153}
154
155impl<'a> IntoIterator for &'a AttributeMappings {
156 type IntoIter = hash_map::Iter<'a, String, AttrId>;
157 type Item = (&'a String, &'a AttrId);
158
159 fn into_iter(self) -> Self::IntoIter {
160 self.attributes.iter()
161 }
162}