extern crate alloc;
use alloc::borrow::Cow;
use alloc::vec::Vec;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Property {
pub name: Cow<'static, str>,
pub value: Cow<'static, str>,
pub propagate: bool,
}
impl Property {
#[must_use]
pub fn local(name: impl Into<Cow<'static, str>>, value: impl Into<Cow<'static, str>>) -> Self {
Self {
name: name.into(),
value: value.into(),
propagate: false,
}
}
#[must_use]
pub fn propagated(
name: impl Into<Cow<'static, str>>,
value: impl Into<Cow<'static, str>>,
) -> Self {
Self {
name: name.into(),
value: value.into(),
propagate: true,
}
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PropertyList {
entries: Vec<Property>,
}
impl PropertyList {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn set(&mut self, p: Property) {
if let Some(existing) = self.entries.iter_mut().find(|e| e.name == p.name) {
*existing = p;
} else {
self.entries.push(p);
}
}
#[must_use]
pub fn with(mut self, p: Property) -> Self {
self.set(p);
self
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&str> {
self.entries
.iter()
.find(|p| p.name == name)
.map(|p| p.value.as_ref())
}
#[must_use]
pub fn entries(&self) -> &[Property] {
&self.entries
}
pub fn propagatable(&self) -> impl Iterator<Item = &Property> {
self.entries.iter().filter(|p| p.propagate)
}
}
#[cfg(test)]
#[allow(clippy::unwrap_used)]
mod tests {
use super::*;
#[test]
fn set_replaces_duplicate() {
let mut list = PropertyList::new();
list.set(Property::local("k", "v1"));
list.set(Property::local("k", "v2"));
assert_eq!(list.entries().len(), 1);
assert_eq!(list.get("k"), Some("v2"));
}
#[test]
fn propagatable_filter() {
let list = PropertyList::new()
.with(Property::local("secret", "sensitive"))
.with(Property::propagated("public", "hashed"));
let propagated: Vec<_> = list.propagatable().collect();
assert_eq!(propagated.len(), 1);
assert_eq!(propagated[0].name, "public");
}
}