kanidmd_lib/valueset/
hexstring.rs

1use crate::prelude::*;
2use crate::schema::SchemaAttribute;
3use crate::valueset::ScimResolveStatus;
4use crate::valueset::{DbValueSetV2, ValueSet};
5
6use std::collections::BTreeSet;
7
8#[derive(Debug, Clone)]
9pub struct ValueSetHexString {
10    set: BTreeSet<String>,
11}
12
13impl ValueSetHexString {
14    pub fn new(s: String) -> Box<Self> {
15        let mut set = BTreeSet::new();
16        set.insert(s);
17        Box::new(ValueSetHexString { set })
18    }
19
20    pub fn push(&mut self, s: &str) -> bool {
21        self.set.insert(s.to_lowercase())
22    }
23
24    pub fn from_dbvs2(data: Vec<String>) -> Result<ValueSet, OperationError> {
25        let set = data.into_iter().collect();
26        Ok(Box::new(ValueSetHexString { set }))
27    }
28
29    // We need to allow this, because rust doesn't allow us to impl FromIterator on foreign
30    // types, and str is foreign
31    #[allow(clippy::should_implement_trait)]
32    pub fn from_iter<'a, T>(iter: T) -> Option<Box<Self>>
33    where
34        T: IntoIterator<Item = &'a str>,
35    {
36        let set = iter.into_iter().map(str::to_string).collect();
37        Some(Box::new(ValueSetHexString { set }))
38    }
39}
40
41impl ValueSetT for ValueSetHexString {
42    fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError> {
43        match value {
44            Value::HexString(s) => Ok(self.set.insert(s)),
45            _ => {
46                debug_assert!(false);
47                Err(OperationError::InvalidValueState)
48            }
49        }
50    }
51
52    fn clear(&mut self) {
53        self.set.clear();
54    }
55
56    fn remove(&mut self, pv: &PartialValue, _cid: &Cid) -> bool {
57        match pv {
58            PartialValue::HexString(s) => self.set.remove(s),
59            _ => {
60                debug_assert!(false);
61                true
62            }
63        }
64    }
65
66    fn contains(&self, pv: &PartialValue) -> bool {
67        match pv {
68            PartialValue::HexString(s) => self.set.contains(s.as_str()),
69            _ => false,
70        }
71    }
72
73    fn substring(&self, pv: &PartialValue) -> bool {
74        match pv {
75            PartialValue::HexString(s2) => self.set.iter().any(|s1| s1.contains(s2)),
76            _ => {
77                debug_assert!(false);
78                false
79            }
80        }
81    }
82
83    fn startswith(&self, pv: &PartialValue) -> bool {
84        match pv {
85            PartialValue::HexString(s2) => self.set.iter().any(|s1| s1.starts_with(s2)),
86            _ => {
87                debug_assert!(false);
88                false
89            }
90        }
91    }
92
93    fn endswith(&self, pv: &PartialValue) -> bool {
94        match pv {
95            PartialValue::HexString(s2) => self.set.iter().any(|s1| s1.ends_with(s2)),
96            _ => {
97                debug_assert!(false);
98                false
99            }
100        }
101    }
102
103    fn lessthan(&self, _pv: &PartialValue) -> bool {
104        false
105    }
106
107    fn len(&self) -> usize {
108        self.set.len()
109    }
110
111    fn generate_idx_eq_keys(&self) -> Vec<String> {
112        self.set.iter().cloned().collect()
113    }
114
115    fn syntax(&self) -> SyntaxType {
116        SyntaxType::HexString
117    }
118
119    fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
120        self.set.iter().all(|s| {
121            Value::validate_str_escapes(s.as_str())
122                && Value::validate_singleline(s.as_str())
123                && Value::validate_hexstr(s.as_str())
124        })
125    }
126
127    fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
128        Box::new(self.set.iter().cloned())
129    }
130
131    fn to_scim_value(&self) -> Option<ScimResolveStatus> {
132        let mut iter = self.set.iter().cloned();
133        if self.len() == 1 {
134            let v = iter.next().unwrap_or_default();
135            Some(v.into())
136        } else {
137            let arr = iter.collect::<Vec<_>>();
138            Some(arr.into())
139        }
140    }
141
142    fn to_db_valueset_v2(&self) -> DbValueSetV2 {
143        DbValueSetV2::HexString(self.set.iter().cloned().collect())
144    }
145
146    fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
147        Box::new(self.set.iter().cloned().map(PartialValue::HexString))
148    }
149
150    fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_> {
151        Box::new(self.set.iter().cloned().map(Value::HexString))
152    }
153
154    fn equal(&self, other: &ValueSet) -> bool {
155        if let Some(other) = other.as_hexstring_set() {
156            &self.set == other
157        } else {
158            debug_assert!(false);
159            false
160        }
161    }
162
163    fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
164        if let Some(b) = other.as_hexstring_set() {
165            mergesets!(self.set, b)
166        } else {
167            debug_assert!(false);
168            Err(OperationError::InvalidValueState)
169        }
170    }
171
172    fn as_hexstring_set(&self) -> Option<&BTreeSet<String>> {
173        Some(&self.set)
174    }
175}
176
177#[cfg(test)]
178mod tests {
179    use super::ValueSetHexString;
180    use crate::prelude::ValueSet;
181
182    #[test]
183    fn test_scim_hexstring() {
184        let vs: ValueSet =
185            ValueSetHexString::new("D68475C760A7A0F6A924C28F095573A967F600D6".to_string());
186        crate::valueset::scim_json_reflexive(&vs, r#""D68475C760A7A0F6A924C28F095573A967F600D6""#);
187    }
188}