1use std::{
8 self,
9 convert::TryFrom,
10 fmt,
11 io::{Read, Write},
12 str::FromStr,
13 sync::atomic::{AtomicUsize, Ordering},
14 u16, u32,
15};
16
17use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
18use serde_json::{self, json};
19
20use crate::types::{
21 byte_string::ByteString,
22 encoding::*,
23 guid::Guid,
24 node_ids::{ObjectId, ReferenceTypeId},
25 status_codes::StatusCode,
26 string::*,
27};
28
29#[derive(Eq, PartialEq, Clone, Debug, Hash)]
31pub enum Identifier {
32 Numeric(u32),
33 String(UAString),
34 Guid(Guid),
35 ByteString(ByteString),
36}
37
38impl fmt::Display for Identifier {
39 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
40 match self {
41 Identifier::Numeric(v) => write!(f, "i={}", *v),
42 Identifier::String(v) => write!(f, "s={}", v),
43 Identifier::Guid(v) => write!(f, "g={:?}", v),
44 Identifier::ByteString(v) => write!(f, "b={}", v.as_base64()),
45 }
46 }
47}
48
49impl FromStr for Identifier {
50 type Err = ();
51
52 fn from_str(s: &str) -> Result<Self, Self::Err> {
53 if s.len() < 2 {
54 Err(())
55 } else {
56 let k = &s[..2];
57 let v = &s[2..];
58 match k {
59 "i=" => v.parse::<u32>().map(|v| v.into()).map_err(|_| ()),
60 "s=" => Ok(UAString::from(v).into()),
61 "g=" => Guid::from_str(v).map(|v| v.into()).map_err(|_| ()),
62 "b=" => ByteString::from_base64(v).map(|v| v.into()).ok_or(()),
63 _ => Err(()),
64 }
65 }
66 }
67}
68
69impl From<i32> for Identifier {
70 fn from(v: i32) -> Self {
71 Identifier::Numeric(v as u32)
72 }
73}
74
75impl From<u32> for Identifier {
76 fn from(v: u32) -> Self {
77 Identifier::Numeric(v as u32)
78 }
79}
80
81impl<'a> From<&'a str> for Identifier {
82 fn from(v: &'a str) -> Self {
83 Identifier::from(UAString::from(v))
84 }
85}
86
87impl From<&String> for Identifier {
88 fn from(v: &String) -> Self {
89 Identifier::from(UAString::from(v))
90 }
91}
92
93impl From<String> for Identifier {
94 fn from(v: String) -> Self {
95 Identifier::from(UAString::from(v))
96 }
97}
98
99impl From<UAString> for Identifier {
100 fn from(v: UAString) -> Self {
101 Identifier::String(v)
102 }
103}
104
105impl From<Guid> for Identifier {
106 fn from(v: Guid) -> Self {
107 Identifier::Guid(v)
108 }
109}
110
111impl From<ByteString> for Identifier {
112 fn from(v: ByteString) -> Self {
113 Identifier::ByteString(v)
114 }
115}
116
117#[derive(Debug)]
118pub struct NodeIdError;
119
120impl fmt::Display for NodeIdError {
121 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
122 write!(f, "NodeIdError")
123 }
124}
125
126impl std::error::Error for NodeIdError {}
127
128#[derive(PartialEq, Eq, Clone, Debug, Hash)]
130pub struct NodeId {
131 pub namespace: u16,
133 pub identifier: Identifier,
135}
136
137impl fmt::Display for NodeId {
138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
139 if self.namespace != 0 {
140 write!(f, "ns={};{}", self.namespace, self.identifier)
141 } else {
142 write!(f, "{}", self.identifier)
143 }
144 }
145}
146
147#[derive(Serialize, Deserialize)]
168struct JsonNodeId {
169 #[serde(skip_serializing_if = "Option::is_none")]
170 #[serde(rename = "Type")]
171 id_type: Option<u32>,
172 #[serde(rename = "Id")]
173 id: serde_json::Value,
174 #[serde(skip_serializing_if = "Option::is_none")]
175 #[serde(rename = "Namespace")]
176 namespace: Option<serde_json::Value>,
177}
178
179impl Serialize for NodeId {
180 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
181 where
182 S: Serializer,
183 {
184 let (id_type, id) = match &self.identifier {
185 Identifier::Numeric(id) => (None, json!(id)),
186 Identifier::String(id) => (Some(1), json!(id.as_ref())),
187 Identifier::Guid(id) => (Some(2), json!(id.to_string())),
188 Identifier::ByteString(id) => (Some(3), json!(id.as_base64())),
189 };
190 let namespace = if self.namespace == 0 {
192 None
193 } else {
194 Some(json!(self.namespace))
195 };
196
197 let json = JsonNodeId {
198 id_type,
199 id,
200 namespace,
201 };
202 json.serialize(serializer)
203 }
204}
205
206impl<'de> Deserialize<'de> for NodeId {
207 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
208 where
209 D: Deserializer<'de>,
210 {
211 let v = JsonNodeId::deserialize(deserializer)?;
212 let namespace = if let Some(namespace) = v.namespace {
214 let namespace = namespace
215 .as_u64()
216 .ok_or_else(|| de::Error::custom("Expected numeric namespace index"))?;
217 if namespace > u16::MAX as u64 {
218 return Err(de::Error::custom("Numeric namespace index is out of range"));
219 }
220 namespace as u16
221 } else {
222 0
223 };
224 let id_type = v.id_type.unwrap_or(0);
226 match id_type {
227 0 => {
228 let v =
230 v.id.as_u64()
231 .ok_or_else(|| de::Error::custom("Expected Numeric identifier"))?;
232 Ok(NodeId::new(namespace, v as u32))
233 }
234 1 => {
235 let v =
237 v.id.as_str()
238 .ok_or_else(|| de::Error::custom("Expected String identifier"))?;
239 if v.is_empty() {
240 Err(de::Error::custom("String identifier is empty"))
241 } else {
242 Ok(NodeId::new(namespace, String::from(v)))
243 }
244 }
245 2 => {
246 let v =
248 v.id.as_str()
249 .ok_or_else(|| de::Error::custom("Expected Guid identifier"))?;
250 if v.is_empty() {
251 Err(de::Error::custom("Guid identifier is empty"))
252 } else {
253 let v = Guid::from_str(v)
254 .map_err(|_| de::Error::custom("Error parsing Guid identifier"))?;
255 Ok(NodeId::new(namespace, v))
256 }
257 }
258 3 => {
259 let v =
261 v.id.as_str()
262 .ok_or_else(|| de::Error::custom("Expected ByteString identifier"))?;
263 if v.is_empty() {
264 Err(de::Error::custom("ByteString identifier is empty"))
265 } else {
266 let v = ByteString::from_base64(v)
267 .ok_or_else(|| de::Error::custom("Error parsing ByteString identifier"))?;
268 Ok(NodeId::new(namespace, v))
269 }
270 }
271 _ => Err(de::Error::custom("Invalid IdType")),
272 }
273 }
274}
275
276impl BinaryEncoder<NodeId> for NodeId {
277 fn byte_len(&self) -> usize {
278 let size: usize = match self.identifier {
280 Identifier::Numeric(value) => {
281 if self.namespace == 0 && value <= 255 {
282 2
283 } else if self.namespace <= 255 && value <= 65535 {
284 4
285 } else {
286 7
287 }
288 }
289 Identifier::String(ref value) => 3 + value.byte_len(),
290 Identifier::Guid(ref value) => 3 + value.byte_len(),
291 Identifier::ByteString(ref value) => 3 + value.byte_len(),
292 };
293 size
294 }
295
296 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
297 let mut size: usize = 0;
298 match &self.identifier {
300 Identifier::Numeric(value) => {
301 if self.namespace == 0 && *value <= 255 {
302 size += write_u8(stream, 0x0)?;
304 size += write_u8(stream, *value as u8)?;
305 } else if self.namespace <= 255 && *value <= 65535 {
306 size += write_u8(stream, 0x1)?;
308 size += write_u8(stream, self.namespace as u8)?;
309 size += write_u16(stream, *value as u16)?;
310 } else {
311 size += write_u8(stream, 0x2)?;
313 size += write_u16(stream, self.namespace)?;
314 size += write_u32(stream, *value)?;
315 }
316 }
317 Identifier::String(value) => {
318 size += write_u8(stream, 0x3)?;
319 size += write_u16(stream, self.namespace)?;
320 size += value.encode(stream)?;
321 }
322 Identifier::Guid(value) => {
323 size += write_u8(stream, 0x4)?;
324 size += write_u16(stream, self.namespace)?;
325 size += value.encode(stream)?;
326 }
327 Identifier::ByteString(value) => {
328 size += write_u8(stream, 0x5)?;
329 size += write_u16(stream, self.namespace)?;
330 size += value.encode(stream)?;
331 }
332 }
333 assert_eq!(size, self.byte_len());
334 Ok(size)
335 }
336
337 fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
338 let identifier = read_u8(stream)?;
339 let node_id = match identifier {
340 0x0 => {
341 let namespace = 0;
342 let value = read_u8(stream)?;
343 NodeId::new(namespace, u32::from(value))
344 }
345 0x1 => {
346 let namespace = read_u8(stream)?;
347 let value = read_u16(stream)?;
348 NodeId::new(u16::from(namespace), u32::from(value))
349 }
350 0x2 => {
351 let namespace = read_u16(stream)?;
352 let value = read_u32(stream)?;
353 NodeId::new(namespace, value)
354 }
355 0x3 => {
356 let namespace = read_u16(stream)?;
357 let value = UAString::decode(stream, decoding_options)?;
358 NodeId::new(namespace, value)
359 }
360 0x4 => {
361 let namespace = read_u16(stream)?;
362 let value = Guid::decode(stream, decoding_options)?;
363 NodeId::new(namespace, value)
364 }
365 0x5 => {
366 let namespace = read_u16(stream)?;
367 let value = ByteString::decode(stream, decoding_options)?;
368 NodeId::new(namespace, value)
369 }
370 _ => {
371 error!("Unrecognized node id type {}", identifier);
372 return Err(StatusCode::BadDecodingError);
373 }
374 };
375 Ok(node_id)
376 }
377}
378
379impl FromStr for NodeId {
380 type Err = StatusCode;
381 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
382 use regex::Regex;
383
384 lazy_static! {
397 static ref RE: Regex = Regex::new(r"^(ns=(?P<ns>[0-9]+);)?(?P<t>[isgb]=.+)$").unwrap();
399 }
400
401 let captures = RE.captures(s).ok_or(StatusCode::BadNodeIdInvalid)?;
402
403 let namespace = if let Some(ns) = captures.name("ns") {
405 ns.as_str()
406 .parse::<u16>()
407 .map_err(|_| StatusCode::BadNodeIdInvalid)?
408 } else {
409 0
410 };
411
412 let t = captures.name("t").unwrap();
414 Identifier::from_str(t.as_str())
415 .map(|t| NodeId::new(namespace, t))
416 .map_err(|_| StatusCode::BadNodeIdInvalid)
417 }
418}
419
420impl From<&NodeId> for NodeId {
421 fn from(v: &NodeId) -> Self {
422 v.clone()
423 }
424}
425
426impl Into<String> for NodeId {
427 fn into(self) -> String {
428 self.to_string()
429 }
430}
431
432impl<'a> From<(u16, &'a str)> for NodeId {
433 fn from(v: (u16, &'a str)) -> Self {
434 Self::new(v.0, UAString::from(v.1))
435 }
436}
437
438impl From<(u16, UAString)> for NodeId {
439 fn from(v: (u16, UAString)) -> Self {
440 Self::new(v.0, v.1)
441 }
442}
443
444impl From<(u16, u32)> for NodeId {
445 fn from(v: (u16, u32)) -> Self {
446 Self::new(v.0, v.1)
447 }
448}
449
450impl From<(u16, Guid)> for NodeId {
451 fn from(v: (u16, Guid)) -> Self {
452 Self::new(v.0, v.1)
453 }
454}
455
456impl From<(u16, ByteString)> for NodeId {
457 fn from(v: (u16, ByteString)) -> Self {
458 Self::new(v.0, v.1)
459 }
460}
461
462static NEXT_NODE_ID_NUMERIC: AtomicUsize = AtomicUsize::new(0);
463
464impl Default for NodeId {
465 fn default() -> Self {
466 NodeId::null()
467 }
468}
469
470impl NodeId {
471 pub fn new<T>(namespace: u16, value: T) -> NodeId
474 where
475 T: 'static + Into<Identifier>,
476 {
477 NodeId {
478 namespace,
479 identifier: value.into(),
480 }
481 }
482
483 pub fn root_folder_id() -> NodeId {
485 ObjectId::RootFolder.into()
486 }
487
488 pub fn objects_folder_id() -> NodeId {
490 ObjectId::ObjectsFolder.into()
491 }
492
493 pub fn types_folder_id() -> NodeId {
495 ObjectId::TypesFolder.into()
496 }
497
498 pub fn views_folder_id() -> NodeId {
500 ObjectId::ViewsFolder.into()
501 }
502
503 pub fn is_null(&self) -> bool {
505 self.namespace == 0 && self.identifier == Identifier::Numeric(0)
506 }
507
508 pub fn null() -> NodeId {
510 NodeId::new(0, 0u32)
511 }
512
513 pub fn next_numeric(namespace: u16) -> NodeId {
515 NodeId::new(
516 namespace,
517 NEXT_NODE_ID_NUMERIC.fetch_add(1, Ordering::SeqCst) as u32,
518 )
519 }
520
521 pub fn as_object_id(&self) -> std::result::Result<ObjectId, NodeIdError> {
523 match self.identifier {
524 Identifier::Numeric(id) if self.namespace == 0 => {
525 ObjectId::try_from(id).map_err(|_| NodeIdError)
526 }
527 _ => Err(NodeIdError),
528 }
529 }
530
531 pub fn as_reference_type_id(&self) -> std::result::Result<ReferenceTypeId, NodeIdError> {
532 if self.is_null() {
535 Err(NodeIdError)
536 } else {
537 match self.identifier {
538 Identifier::Numeric(id) if self.namespace == 0 => {
539 ReferenceTypeId::try_from(id).map_err(|_| NodeIdError)
540 }
541 _ => Err(NodeIdError),
542 }
543 }
544 }
545
546 pub fn is_numeric(&self) -> bool {
548 matches!(self.identifier, Identifier::Numeric(_))
549 }
550
551 pub fn is_string(&self) -> bool {
553 matches!(self.identifier, Identifier::String(_))
554 }
555
556 pub fn is_guid(&self) -> bool {
558 matches!(self.identifier, Identifier::Guid(_))
559 }
560
561 pub fn is_byte_string(&self) -> bool {
563 matches!(self.identifier, Identifier::ByteString(_))
564 }
565}