proxmox_api/
path.rs

1#[derive(Debug, Clone, PartialEq)]
2pub enum PathElement {
3    Literal(String),
4    Placeholder(String),
5}
6
7impl From<&str> for PathElement {
8    fn from(value: &str) -> Self {
9        if value.starts_with('{') && value.ends_with('}') {
10            Self::Placeholder(value[1..value.len() - 1].to_string())
11        } else {
12            Self::Literal(value.to_string())
13        }
14    }
15}
16
17impl core::fmt::Display for PathElement {
18    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
19        match self {
20            PathElement::Literal(l) => write!(f, "{l}"),
21            PathElement::Placeholder(p) => write!(f, "{{{p}}}"),
22        }
23    }
24}
25
26impl PathElement {
27    pub fn matches(&self, other: &Self) -> bool {
28        match (self, other) {
29            (Self::Placeholder(_), _) => true,
30            (Self::Literal(s), Self::Literal(o)) => s == o,
31            (Self::Literal(_), Self::Placeholder(_)) => false,
32        }
33    }
34
35    pub fn as_string_without_brackets(&self) -> &str {
36        match self {
37            PathElement::Literal(v) | PathElement::Placeholder(v) => &v,
38        }
39    }
40}
41
42#[derive(Debug, Clone, PartialEq)]
43pub struct Path {
44    elements: Vec<PathElement>,
45}
46
47impl core::fmt::Display for Path {
48    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
49        if let Some(err) = self.elements.iter().find_map(|v| write!(f, "/{v}").err()) {
50            return Err(err);
51        }
52
53        Ok(())
54    }
55}
56
57impl TryFrom<&str> for Path {
58    type Error = ();
59
60    fn try_from(value: &str) -> Result<Self, ()> {
61        if !value.starts_with('/') {
62            return Err(());
63        }
64
65        let elements = value
66            .split('/')
67            .skip(1)
68            .map(|v| PathElement::from(v))
69            .collect();
70
71        Ok(Self { elements })
72    }
73}
74
75impl Path {
76    pub fn matches<'a>(&self, other: impl IntoIterator<Item = &'a str>) -> bool {
77        let mut elements = self.elements.iter();
78        let mut other = other.into_iter();
79        let mut zipped = (&mut elements).zip(&mut other);
80
81        for (l, r) in &mut zipped {
82            if let PathElement::Literal(literal) = l {
83                if literal != r {
84                    return false;
85                }
86            }
87        }
88
89        other.next().is_none() && elements.next().is_none()
90    }
91
92    pub fn iter(&self) -> impl Iterator<Item = &'_ PathElement> + '_ {
93        self.elements.iter()
94    }
95}