immigrant_schema/
attribute.rs

1#[derive(Clone, Debug)]
2pub enum AttributeValue {
3	// Field is not set
4	Unset,
5	// Field is set, but value is not specified
6	Set,
7	String(String),
8}
9impl TryFrom<AttributeValue> for bool {
10	type Error = &'static str;
11
12	fn try_from(value: AttributeValue) -> Result<Self, Self::Error> {
13		Ok(match value {
14			AttributeValue::Unset => false,
15			AttributeValue::Set => true,
16			AttributeValue::String(_) => return Err("expected boolean, got string"),
17		})
18	}
19}
20impl TryFrom<AttributeValue> for String {
21	type Error = &'static str;
22
23	fn try_from(value: AttributeValue) -> Result<Self, Self::Error> {
24		Ok(match value {
25			AttributeValue::Unset => return Err("missing string attribute"),
26			AttributeValue::Set => return Err("missing attribute value"),
27			AttributeValue::String(s) => s,
28		})
29	}
30}
31
32#[derive(Debug, Clone)]
33pub struct AttributeField {
34	pub key: String,
35	pub value: AttributeValue,
36}
37
38#[derive(Debug, Clone)]
39pub struct Attribute {
40	pub name: String,
41	pub fields: Vec<AttributeField>,
42}
43
44pub struct DuplicateAttributeError;
45impl From<DuplicateAttributeError> for &'static str {
46	fn from(_value: DuplicateAttributeError) -> Self {
47		"duplicate attribute"
48	}
49}
50
51#[derive(Debug, Clone)]
52pub struct AttributeList(pub Vec<Attribute>);
53impl AttributeList {
54	pub fn iter_fields(&self, attre: &str, fielde: &str, mut cb: impl FnMut(&AttributeValue)) {
55		for attr in &self.0 {
56			if attr.name != attre {
57				continue;
58			}
59			for field in &attr.fields {
60				if field.key != fielde {
61					continue;
62				}
63				cb(&field.value);
64			}
65		}
66	}
67	pub fn get_multi<T>(&self, attre: &str, fielde: &str) -> Result<Vec<T>, T::Error>
68	where
69		T: TryFrom<AttributeValue>,
70	{
71		let mut value = Vec::new();
72		self.iter_fields(attre, fielde, |v| value.push(v.clone()));
73		let mut parsed = Vec::new();
74		for v in value {
75			parsed.push(T::try_from(v)?);
76		}
77		Ok(parsed)
78	}
79	pub fn try_get_single<T>(&self, attre: &str, fielde: &str) -> Result<Option<T>, T::Error>
80	where
81		T: TryFrom<AttributeValue>,
82		T::Error: From<DuplicateAttributeError>,
83	{
84		let v = self.get_multi::<T>(attre, fielde)?;
85		if v.len() > 1 {
86			return Err(DuplicateAttributeError.into());
87		}
88		Ok(v.into_iter().next())
89	}
90	pub fn get_single<T>(&self, attre: &str, fielde: &str) -> Result<T, T::Error>
91	where
92		T: TryFrom<AttributeValue>,
93		T::Error: From<DuplicateAttributeError>,
94	{
95		let v = self.get_multi::<T>(attre, fielde)?;
96		if v.len() > 1 {
97			return Err(DuplicateAttributeError.into());
98		}
99		match v.into_iter().next() { Some(v) => {
100			Ok(v)
101		} _ => {
102			T::try_from(AttributeValue::Unset)
103		}}
104	}
105}