melodium_common/descriptor/
identifier.rs1use 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}