opcua_types/node_id/
identifier.rs

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/// The kind of identifier, numeric, string, guid or byte
10#[derive(Eq, PartialEq, Clone, Debug)]
11pub enum Identifier {
12    /// Numeric node ID identifier. i=123
13    Numeric(u32),
14    /// String node ID identifier, s=...
15    String(UAString),
16    /// GUID node ID identifier, g=...
17    Guid(Guid),
18    /// Opaque node ID identifier, o=...
19    ByteString(ByteString),
20}
21
22/// Value used as discriminator when hashing numeric node IDs.
23pub const IDENTIFIER_HASH_NUMERIC: u8 = 0;
24/// Value used as discriminator when hashing string node IDs.
25pub const IDENTIFIER_HASH_STRING: u8 = 1;
26/// Value used as discriminator when hashing Guid node IDs.
27pub const IDENTIFIER_HASH_GUID: u8 = 2;
28/// Value used as discriminator when hashing byte string node IDs.
29pub 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}