kanidmd_lib/valueset/
uint32.rs

1use crate::prelude::*;
2use crate::schema::SchemaAttribute;
3use crate::valueset::{
4    DbValueSetV2, ScimResolveStatus, ValueSet, ValueSetResolveStatus, ValueSetScimPut,
5};
6use kanidm_proto::scim_v1::JsonValue;
7use smolset::SmolSet;
8
9#[derive(Debug, Clone)]
10pub struct ValueSetUint32 {
11    set: SmolSet<[u32; 1]>,
12}
13
14impl ValueSetUint32 {
15    pub fn new(b: u32) -> Box<Self> {
16        let mut set = SmolSet::new();
17        set.insert(b);
18        Box::new(ValueSetUint32 { set })
19    }
20
21    pub fn push(&mut self, b: u32) -> bool {
22        self.set.insert(b)
23    }
24
25    pub fn from_dbvs2(data: Vec<u32>) -> Result<ValueSet, OperationError> {
26        let set = data.into_iter().collect();
27        Ok(Box::new(ValueSetUint32 { set }))
28    }
29
30    // We need to allow this, because rust doesn't allow us to impl FromIterator on foreign
31    // types, and u32 is foreign.
32    #[allow(clippy::should_implement_trait)]
33    pub fn from_iter<T>(iter: T) -> Option<Box<Self>>
34    where
35        T: IntoIterator<Item = u32>,
36    {
37        let set = iter.into_iter().collect();
38        Some(Box::new(ValueSetUint32 { set }))
39    }
40}
41
42impl ValueSetScimPut for ValueSetUint32 {
43    fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError> {
44        let value: u32 = serde_json::from_value(value).map_err(|err| {
45            error!(?err, "SCIM uint32 syntax invalid");
46            OperationError::SC0006Uint32SyntaxInvalid
47        })?;
48
49        let mut set = SmolSet::new();
50        set.insert(value);
51
52        Ok(ValueSetResolveStatus::Resolved(Box::new(ValueSetUint32 {
53            set,
54        })))
55    }
56}
57
58impl ValueSetT for ValueSetUint32 {
59    fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError> {
60        match value {
61            Value::Uint32(u) => Ok(self.set.insert(u)),
62            _ => {
63                debug_assert!(false);
64                Err(OperationError::InvalidValueState)
65            }
66        }
67    }
68
69    fn clear(&mut self) {
70        self.set.clear();
71    }
72
73    fn remove(&mut self, pv: &PartialValue, _cid: &Cid) -> bool {
74        match pv {
75            PartialValue::Uint32(u) => self.set.remove(u),
76            _ => {
77                debug_assert!(false);
78                true
79            }
80        }
81    }
82
83    fn contains(&self, pv: &PartialValue) -> bool {
84        match pv {
85            PartialValue::Uint32(u) => self.set.contains(u),
86            _ => false,
87        }
88    }
89
90    fn substring(&self, _pv: &PartialValue) -> bool {
91        false
92    }
93
94    fn startswith(&self, _pv: &PartialValue) -> bool {
95        false
96    }
97
98    fn endswith(&self, _pv: &PartialValue) -> bool {
99        false
100    }
101
102    fn lessthan(&self, pv: &PartialValue) -> bool {
103        match pv {
104            PartialValue::Uint32(u) => self.set.iter().any(|i| i < u),
105            _ => false,
106        }
107    }
108
109    fn len(&self) -> usize {
110        self.set.len()
111    }
112
113    fn generate_idx_eq_keys(&self) -> Vec<String> {
114        self.set.iter().map(|b| b.to_string()).collect()
115    }
116
117    fn syntax(&self) -> SyntaxType {
118        SyntaxType::Uint32
119    }
120
121    fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
122        true
123    }
124
125    fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
126        Box::new(self.set.iter().map(|b| b.to_string()))
127    }
128
129    fn to_scim_value(&self) -> Option<ScimResolveStatus> {
130        if self.len() == 1 {
131            // Because self.len == 1 we know this has to yield a value.
132            let b = self.set.iter().copied().next().unwrap_or_default();
133            Some(b.into())
134        } else {
135            // Nothing is MV for this today
136            None
137        }
138    }
139
140    fn to_db_valueset_v2(&self) -> DbValueSetV2 {
141        DbValueSetV2::Uint32(self.set.iter().cloned().collect())
142    }
143
144    fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
145        Box::new(self.set.iter().copied().map(PartialValue::new_uint32))
146    }
147
148    fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_> {
149        Box::new(self.set.iter().copied().map(Value::new_uint32))
150    }
151
152    fn equal(&self, other: &ValueSet) -> bool {
153        if let Some(other) = other.as_uint32_set() {
154            &self.set == other
155        } else {
156            debug_assert!(false);
157            false
158        }
159    }
160
161    fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
162        if let Some(b) = other.as_uint32_set() {
163            mergesets!(self.set, b)
164        } else {
165            debug_assert!(false);
166            Err(OperationError::InvalidValueState)
167        }
168    }
169
170    fn to_uint32_single(&self) -> Option<u32> {
171        if self.set.len() == 1 {
172            self.set.iter().copied().take(1).next()
173        } else {
174            None
175        }
176    }
177
178    fn as_uint32_set(&self) -> Option<&SmolSet<[u32; 1]>> {
179        Some(&self.set)
180    }
181}
182
183#[cfg(test)]
184mod tests {
185    use super::ValueSetUint32;
186    use crate::prelude::*;
187
188    #[test]
189    fn test_valueset_basic() {
190        let mut vs = ValueSetUint32::new(0);
191        assert_eq!(vs.insert_checked(Value::new_uint32(0)), Ok(false));
192        assert_eq!(vs.insert_checked(Value::new_uint32(1)), Ok(true));
193        assert_eq!(vs.insert_checked(Value::new_uint32(1)), Ok(false));
194    }
195
196    #[test]
197    fn test_scim_uint32() {
198        let vs: ValueSet = ValueSetUint32::new(69);
199        crate::valueset::scim_json_reflexive(&vs, "69");
200
201        // Test that we can parse json values into a valueset.
202        crate::valueset::scim_json_put_reflexive::<ValueSetUint32>(&vs, &[])
203    }
204}