authly_common/
service.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! Authly service utilities and helpers

use std::collections::{hash_map, HashMap};

use fnv::FnvHashSet;

use crate::id::AttrId;

/// A namespaced property mapping maps human-readable property and attribute labels to [AttrId]s.
#[derive(Clone, Default)]
pub struct NamespacePropertyMapping {
    namespaces: HashMap<String, PropertyMappings>,
}

/// A property mapping maps human-readable property and attribute labels to [AttrId]s.
#[derive(Clone, Default)]
pub struct PropertyMappings {
    properties: HashMap<String, AttributeMappings>,
}

/// Attribute mappings for a property.
#[derive(Clone, Default)]
pub struct AttributeMappings {
    attributes: HashMap<String, AttrId>,
}

/// A trait describing a namespaced attribute.
pub trait NamespacedPropertyAttribute {
    /// The namespace label of the attribute
    fn namespace(&self) -> &str;

    /// The property label of the attribute
    fn property(&self) -> &str;

    /// The attribute of the namespaced property
    fn attribute(&self) -> &str;
}

impl<'a> NamespacedPropertyAttribute for (&'a str, &'a str, &'a str) {
    fn namespace(&self) -> &str {
        self.0
    }

    fn property(&self) -> &str {
        self.1
    }

    fn attribute(&self) -> &str {
        self.2
    }
}

impl NamespacePropertyMapping {
    /// Get a mutable reference to the namespace
    pub fn namespace_mut(&mut self, namespace_label: String) -> &mut PropertyMappings {
        self.namespaces.entry(namespace_label).or_default()
    }

    /// Get the object ID of a single namespace/property/attribute label triple, if found.
    pub fn attribute_id(&self, attr: &impl NamespacedPropertyAttribute) -> Option<AttrId> {
        self.namespaces
            .get(attr.namespace())?
            .properties
            .get(attr.property())?
            .attributes
            .get(attr.attribute())
            .cloned()
    }

    /// Translate the given namespace/property/attribute labels to underlying [AttrId]s.
    pub fn translate<'a>(
        &self,
        attributes: impl IntoIterator<Item = (&'a str, &'a str, &'a str)>,
    ) -> FnvHashSet<AttrId> {
        let mut output = FnvHashSet::default();
        for (namespace, prop, attr) in attributes {
            let Some(prop_mappings) = self.namespaces.get(namespace) else {
                continue;
            };
            let Some(attr_mappings) = prop_mappings.properties.get(prop) else {
                continue;
            };
            let Some(attr_id) = attr_mappings.attributes.get(attr) else {
                continue;
            };

            output.insert(*attr_id);
        }

        output
    }
}

impl PropertyMappings {
    /// Get a mutable reference to the attribute mappings of a property.
    pub fn property_mut(&mut self, property_label: String) -> &mut AttributeMappings {
        self.properties.entry(property_label).or_default()
    }
}

impl AttributeMappings {
    /// Put a new attribute id under the attribute label.
    pub fn put(&mut self, attribute_label: String, attribute_id: AttrId) {
        self.attributes
            .entry(attribute_label)
            .insert_entry(attribute_id);
    }
}

impl IntoIterator for NamespacePropertyMapping {
    type IntoIter = hash_map::IntoIter<String, PropertyMappings>;
    type Item = (String, PropertyMappings);

    fn into_iter(self) -> Self::IntoIter {
        self.namespaces.into_iter()
    }
}

impl<'a> IntoIterator for &'a NamespacePropertyMapping {
    type IntoIter = hash_map::Iter<'a, String, PropertyMappings>;
    type Item = (&'a String, &'a PropertyMappings);

    fn into_iter(self) -> Self::IntoIter {
        self.namespaces.iter()
    }
}

impl IntoIterator for PropertyMappings {
    type IntoIter = hash_map::IntoIter<String, AttributeMappings>;
    type Item = (String, AttributeMappings);

    fn into_iter(self) -> Self::IntoIter {
        self.properties.into_iter()
    }
}

impl<'a> IntoIterator for &'a PropertyMappings {
    type IntoIter = hash_map::Iter<'a, String, AttributeMappings>;
    type Item = (&'a String, &'a AttributeMappings);

    fn into_iter(self) -> Self::IntoIter {
        self.properties.iter()
    }
}

impl IntoIterator for AttributeMappings {
    type IntoIter = hash_map::IntoIter<String, AttrId>;
    type Item = (String, AttrId);

    fn into_iter(self) -> Self::IntoIter {
        self.attributes.into_iter()
    }
}

impl<'a> IntoIterator for &'a AttributeMappings {
    type IntoIter = hash_map::Iter<'a, String, AttrId>;
    type Item = (&'a String, &'a AttrId);

    fn into_iter(self) -> Self::IntoIter {
        self.attributes.iter()
    }
}