authly_common/
service.rs

1//! Authly service utilities and helpers
2
3use std::collections::{hash_map, HashMap};
4
5use fnv::FnvHashSet;
6
7use crate::id::AttrId;
8
9/// A namespaced property mapping maps human-readable property and attribute labels to [AttrId]s.
10#[derive(Clone, Default)]
11pub struct NamespacePropertyMapping {
12    namespaces: HashMap<String, PropertyMappings>,
13}
14
15/// A property mapping maps human-readable property and attribute labels to [AttrId]s.
16#[derive(Clone, Default)]
17pub struct PropertyMappings {
18    properties: HashMap<String, AttributeMappings>,
19}
20
21/// Attribute mappings for a property.
22#[derive(Clone, Default)]
23pub struct AttributeMappings {
24    attributes: HashMap<String, AttrId>,
25}
26
27/// A trait describing a namespaced attribute.
28pub trait NamespacedPropertyAttribute {
29    /// The namespace label of the attribute
30    fn namespace(&self) -> &str;
31
32    /// The property label of the attribute
33    fn property(&self) -> &str;
34
35    /// The attribute of the namespaced property
36    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    /// Get a mutable reference to the namespace
55    pub fn namespace_mut(&mut self, namespace_label: String) -> &mut PropertyMappings {
56        self.namespaces.entry(namespace_label).or_default()
57    }
58
59    /// Get the object ID of a single namespace/property/attribute label triple, if found.
60    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    /// Translate the given namespace/property/attribute labels to underlying [AttrId]s.
71    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    /// Get a mutable reference to the attribute mappings of a property.
96    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    /// Put a new attribute id under the attribute label.
103    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}