1use std::{
2 fmt,
3 hash::{Hash, Hasher},
4 str::FromStr,
5};
6
7use crate::{node_id::id_ref::IdentifierRef, ByteString, Guid, GuidRef, UAString};
8
9#[derive(Eq, PartialEq, Clone, Debug)]
11pub enum Identifier {
12 Numeric(u32),
14 String(UAString),
16 Guid(Guid),
18 ByteString(ByteString),
20}
21
22pub const IDENTIFIER_HASH_NUMERIC: u8 = 0;
24pub const IDENTIFIER_HASH_STRING: u8 = 1;
26pub const IDENTIFIER_HASH_GUID: u8 = 2;
28pub const IDENTIFIER_HASH_BYTE_STRING: u8 = 3;
30
31impl std::hash::Hash for Identifier {
32 fn hash<H: Hasher>(&self, state: &mut H) {
33 match self {
34 Identifier::Numeric(v) => {
35 IDENTIFIER_HASH_NUMERIC.hash(state);
36 v.hash(state)
37 }
38 Identifier::String(v) => {
39 IDENTIFIER_HASH_STRING.hash(state);
40 v.as_ref().hash(state)
41 }
42 Identifier::Guid(v) => {
43 IDENTIFIER_HASH_GUID.hash(state);
44 v.as_bytes().hash(state)
45 }
46 Identifier::ByteString(v) => {
47 IDENTIFIER_HASH_BYTE_STRING.hash(state);
48 v.as_ref().hash(state)
49 }
50 }
51 }
52}
53
54impl fmt::Display for Identifier {
55 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56 match self {
57 Identifier::Numeric(v) => write!(f, "i={}", *v),
58 Identifier::String(v) => write!(f, "s={v}"),
59 Identifier::Guid(v) => write!(f, "g={v:?}"),
60 Identifier::ByteString(v) => write!(f, "b={}", v.as_base64()),
61 }
62 }
63}
64
65impl FromStr for Identifier {
66 type Err = ();
67
68 fn from_str(s: &str) -> Result<Self, Self::Err> {
69 if s.len() < 2 {
70 Err(())
71 } else {
72 let k = &s[..2];
73 let v = &s[2..];
74 match k {
75 "i=" => v.parse::<u32>().map(|v| v.into()).map_err(|_| ()),
76 "s=" => Ok(UAString::from(v).into()),
77 "g=" => Guid::from_str(v).map(|v| v.into()).map_err(|_| ()),
78 "b=" => ByteString::from_base64(v).map(|v| v.into()).ok_or(()),
79 _ => Err(()),
80 }
81 }
82 }
83}
84
85impl From<u32> for Identifier {
86 fn from(v: u32) -> Self {
87 Identifier::Numeric(v)
88 }
89}
90
91impl<'a> From<&'a str> for Identifier {
92 fn from(v: &'a str) -> Self {
93 Identifier::from(UAString::from(v))
94 }
95}
96
97impl From<&String> for Identifier {
98 fn from(v: &String) -> Self {
99 Identifier::from(UAString::from(v))
100 }
101}
102
103impl From<String> for Identifier {
104 fn from(v: String) -> Self {
105 Identifier::from(UAString::from(v))
106 }
107}
108
109impl From<UAString> for Identifier {
110 fn from(v: UAString) -> Self {
111 Identifier::String(v)
112 }
113}
114
115impl From<Guid> for Identifier {
116 fn from(v: Guid) -> Self {
117 Identifier::Guid(v)
118 }
119}
120
121impl From<ByteString> for Identifier {
122 fn from(v: ByteString) -> Self {
123 Identifier::ByteString(v)
124 }
125}
126
127macro_rules! impl_identifier_ref {
128 ($x:ident, $t:ty, $h:ident, $eq_p:pat, $h_expr:expr) => {
129 impl_identifier_ref!($x, $t, $h, $eq_p, $h_expr, $x);
130 };
131 ($x:ident, $t:ty, $h:ident, $eq_p:pat, $h_expr:expr, $eq_expr:expr) => {
132 impl PartialEq<Identifier> for $t {
133 fn eq(&self, other: &Identifier) -> bool {
134 match other {
135 $eq_p => $eq_expr == self,
136 _ => false,
137 }
138 }
139 }
140
141 impl IdentifierRef for $t {
142 fn hash_as_identifier<H: Hasher>(&self, state: &mut H) {
143 $h.hash(state);
144 let $x = self;
145 $h_expr.hash(state);
146 }
147 }
148 };
149}
150
151impl_identifier_ref!(x, u32, IDENTIFIER_HASH_NUMERIC, Identifier::Numeric(x), x);
152impl_identifier_ref!(
153 x,
154 &u32,
155 IDENTIFIER_HASH_NUMERIC,
156 Identifier::Numeric(x),
157 x,
158 &x
159);
160impl_identifier_ref!(
161 x,
162 UAString,
163 IDENTIFIER_HASH_STRING,
164 Identifier::String(x),
165 x.as_ref()
166);
167impl_identifier_ref!(
168 x,
169 &UAString,
170 IDENTIFIER_HASH_STRING,
171 Identifier::String(x),
172 x.as_ref(),
173 &x
174);
175impl_identifier_ref!(
176 x,
177 String,
178 IDENTIFIER_HASH_STRING,
179 Identifier::String(x),
180 x.as_str(),
181 x.as_ref()
182);
183impl_identifier_ref!(x, &str, IDENTIFIER_HASH_STRING, Identifier::String(x), x);
184impl_identifier_ref!(x, &String, IDENTIFIER_HASH_STRING, Identifier::String(x), x);
185impl_identifier_ref!(x, Guid, IDENTIFIER_HASH_GUID, Identifier::Guid(x), x);
186impl_identifier_ref!(
187 x,
188 ByteString,
189 IDENTIFIER_HASH_BYTE_STRING,
190 Identifier::ByteString(x),
191 x
192);
193impl_identifier_ref!(x, &Guid, IDENTIFIER_HASH_GUID, Identifier::Guid(x), x, &x);
194impl_identifier_ref!(
195 x,
196 &ByteString,
197 IDENTIFIER_HASH_BYTE_STRING,
198 Identifier::ByteString(x),
199 x,
200 &x
201);
202impl_identifier_ref!(
203 x,
204 &[u8],
205 IDENTIFIER_HASH_BYTE_STRING,
206 Identifier::ByteString(x),
207 x
208);
209impl_identifier_ref!(x, GuidRef<'_>, IDENTIFIER_HASH_GUID, Identifier::Guid(x), x);
210
211impl IdentifierRef for Identifier {
212 fn hash_as_identifier<H: Hasher>(&self, state: &mut H) {
213 self.hash(state);
214 }
215}
216
217impl PartialEq<Identifier> for &Identifier {
218 fn eq(&self, other: &Identifier) -> bool {
219 (*self).eq(other)
220 }
221}
222
223impl IdentifierRef for &Identifier {
224 fn hash_as_identifier<H: Hasher>(&self, state: &mut H) {
225 self.hash(state);
226 }
227}