zerodds_security/
properties.rs1extern crate alloc;
11
12use alloc::borrow::Cow;
13use alloc::vec::Vec;
14
15#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct Property {
22 pub name: Cow<'static, str>,
24 pub value: Cow<'static, str>,
26 pub propagate: bool,
29}
30
31impl Property {
32 #[must_use]
34 pub fn local(name: impl Into<Cow<'static, str>>, value: impl Into<Cow<'static, str>>) -> Self {
35 Self {
36 name: name.into(),
37 value: value.into(),
38 propagate: false,
39 }
40 }
41
42 #[must_use]
44 pub fn propagated(
45 name: impl Into<Cow<'static, str>>,
46 value: impl Into<Cow<'static, str>>,
47 ) -> Self {
48 Self {
49 name: name.into(),
50 value: value.into(),
51 propagate: true,
52 }
53 }
54}
55
56#[derive(Debug, Clone, Default, PartialEq, Eq)]
59pub struct PropertyList {
60 entries: Vec<Property>,
61}
62
63impl PropertyList {
64 #[must_use]
66 pub fn new() -> Self {
67 Self::default()
68 }
69
70 pub fn set(&mut self, p: Property) {
72 if let Some(existing) = self.entries.iter_mut().find(|e| e.name == p.name) {
73 *existing = p;
74 } else {
75 self.entries.push(p);
76 }
77 }
78
79 #[must_use]
81 pub fn with(mut self, p: Property) -> Self {
82 self.set(p);
83 self
84 }
85
86 #[must_use]
88 pub fn get(&self, name: &str) -> Option<&str> {
89 self.entries
90 .iter()
91 .find(|p| p.name == name)
92 .map(|p| p.value.as_ref())
93 }
94
95 #[must_use]
97 pub fn entries(&self) -> &[Property] {
98 &self.entries
99 }
100
101 pub fn propagatable(&self) -> impl Iterator<Item = &Property> {
103 self.entries.iter().filter(|p| p.propagate)
104 }
105}
106
107#[cfg(test)]
108#[allow(clippy::unwrap_used)]
109mod tests {
110 use super::*;
111
112 #[test]
113 fn set_replaces_duplicate() {
114 let mut list = PropertyList::new();
115 list.set(Property::local("k", "v1"));
116 list.set(Property::local("k", "v2"));
117 assert_eq!(list.entries().len(), 1);
118 assert_eq!(list.get("k"), Some("v2"));
119 }
120
121 #[test]
122 fn propagatable_filter() {
123 let list = PropertyList::new()
124 .with(Property::local("secret", "sensitive"))
125 .with(Property::propagated("public", "hashed"));
126 let propagated: Vec<_> = list.propagatable().collect();
127 assert_eq!(propagated.len(), 1);
128 assert_eq!(propagated[0].name, "public");
129 }
130}