Skip to main content

melodium_common/descriptor/
identifier.rs

1use super::Version;
2use core::{
3    convert::TryFrom,
4    fmt::{Display, Formatter},
5    result::Result,
6    str::FromStr,
7};
8
9#[derive(Clone, PartialEq, Eq, Hash, Debug)]
10pub struct Identifier {
11    version: Option<Version>,
12    path: Vec<String>,
13    name: String,
14}
15
16impl Identifier {
17    pub fn new(path: Vec<String>, name: &str) -> Self {
18        if path.is_empty() {
19            panic!("Identifier path cannot be empty.")
20        }
21
22        Self {
23            version: None,
24            path,
25            name: name.to_string(),
26        }
27    }
28
29    pub fn new_versionned(version: &Version, path: Vec<String>, name: &str) -> Self {
30        if path.is_empty() {
31            panic!("Identifier path cannot be empty.")
32        }
33
34        Self {
35            version: Some(version.clone()),
36            path,
37            name: name.to_string(),
38        }
39    }
40
41    pub fn new_optionally_versionned(
42        version: Option<&Version>,
43        path: Vec<String>,
44        name: &str,
45    ) -> Self {
46        if path.is_empty() {
47            panic!("Identifier path cannot be empty.")
48        }
49
50        Self {
51            version: version.cloned(),
52            path,
53            name: name.to_string(),
54        }
55    }
56
57    pub fn version(&self) -> Option<&Version> {
58        self.version.as_ref()
59    }
60
61    pub fn root(&self) -> &String {
62        &self.path.first().unwrap()
63    }
64
65    pub fn path(&self) -> &Vec<String> {
66        &self.path
67    }
68
69    pub fn name(&self) -> &str {
70        &self.name
71    }
72
73    pub fn with_version(&self, version: &Version) -> Self {
74        Self {
75            version: Some(version.clone()),
76            path: self.path.clone(),
77            name: self.name.clone(),
78        }
79    }
80
81    pub fn with_optional_version(&self, version: Option<&Version>) -> Self {
82        Self {
83            version: version.cloned(),
84            path: self.path.clone(),
85            name: self.name.clone(),
86        }
87    }
88
89    pub fn without_version(&self) -> Self {
90        Self {
91            version: None,
92            path: self.path.clone(),
93            name: self.name.clone(),
94        }
95    }
96}
97
98impl Display for Identifier {
99    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
100        write!(f, "{}::{}", self.path.join("/"), self.name)
101    }
102}
103
104impl FromStr for Identifier {
105    type Err = String;
106
107    fn from_str(s: &str) -> Result<Self, Self::Err> {
108        Self::try_from(s)
109    }
110}
111
112impl Ord for Identifier {
113    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
114        let c = self.to_string().cmp(&other.to_string());
115        if c == core::cmp::Ordering::Equal {
116            if let (Some(s), Some(o)) = (self.version(), other.version()) {
117                s.cmp(o)
118            } else {
119                c
120            }
121        } else {
122            c
123        }
124    }
125}
126
127impl PartialOrd for Identifier {
128    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
129        let c = self.to_string().partial_cmp(&other.to_string());
130        if c == Some(core::cmp::Ordering::Equal) {
131            if let (Some(s), Some(o)) = (self.version(), other.version()) {
132                s.partial_cmp(o)
133            } else {
134                c
135            }
136        } else {
137            c
138        }
139    }
140}
141
142impl TryFrom<&str> for Identifier {
143    type Error = String;
144
145    fn try_from(value: &str) -> Result<Self, Self::Error> {
146        let full = value.split("::").collect::<Vec<_>>();
147        if full.len() == 2 {
148            let path = full[0];
149            let name = full[1];
150
151            let path = path.split('/').map(|s| s.to_string()).collect::<Vec<_>>();
152            if path.len() >= 1 {
153                Ok(Self {
154                    version: None,
155                    path,
156                    name: name.to_string(),
157                })
158            } else {
159                Err(value.to_string())
160            }
161        } else {
162            Err(value.to_string())
163        }
164    }
165}
166
167impl TryFrom<&String> for Identifier {
168    type Error = String;
169
170    fn try_from(value: &String) -> Result<Self, Self::Error> {
171        Self::try_from(value.as_str())
172    }
173}