Skip to main content

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.split('/').skip(1).map(PathElement::from).collect();
66
67        Ok(Self { elements })
68    }
69}
70
71impl Path {
72    pub fn matches<'a>(&self, other: impl IntoIterator<Item = &'a str>) -> bool {
73        let mut elements = self.elements.iter();
74        let mut other = other.into_iter();
75        let mut zipped = (&mut elements).zip(&mut other);
76
77        for (l, r) in &mut zipped {
78            if let PathElement::Literal(literal) = l
79                && literal != r
80            {
81                return false;
82            }
83        }
84
85        other.next().is_none() && elements.next().is_none()
86    }
87
88    pub fn iter(&self) -> impl Iterator<Item = &'_ PathElement> + '_ {
89        self.elements.iter()
90    }
91}