opcua_types/node_id/
json.rs1use std::io::{Read, Write};
2use std::str::FromStr;
3
4use tracing::warn;
5
6use super::{Identifier, NodeId};
7use crate::{json::*, ByteString, Error, Guid, UAString};
8
9enum RawIdentifier {
30 String(String),
31 Integer(u32),
32}
33
34impl JsonEncodable for NodeId {
35 fn encode(
36 &self,
37 stream: &mut JsonStreamWriter<&mut dyn Write>,
38 ctx: &crate::json::Context<'_>,
39 ) -> crate::EncodingResult<()> {
40 stream.begin_object()?;
41 match &self.identifier {
42 super::Identifier::Numeric(n) => {
43 stream.name("Id")?;
44 stream.number_value(*n)?;
45 }
46 super::Identifier::String(uastring) => {
47 stream.name("IdType")?;
48 stream.number_value(1)?;
49 stream.name("Id")?;
50 JsonEncodable::encode(uastring, stream, ctx)?;
51 }
52 super::Identifier::Guid(guid) => {
53 stream.name("IdType")?;
54 stream.number_value(2)?;
55 stream.name("Id")?;
56 JsonEncodable::encode(guid, stream, ctx)?;
57 }
58 super::Identifier::ByteString(byte_string) => {
59 stream.name("IdType")?;
60 stream.number_value(3)?;
61 stream.name("Id")?;
62 JsonEncodable::encode(byte_string, stream, ctx)?;
63 }
64 }
65 if self.namespace != 0 {
66 stream.name("Namespace")?;
67 stream.number_value(self.namespace)?;
68 }
69 stream.end_object()?;
70 Ok(())
71 }
72}
73
74impl JsonDecodable for NodeId {
75 fn decode(
76 stream: &mut JsonStreamReader<&mut dyn Read>,
77 _ctx: &Context<'_>,
78 ) -> crate::EncodingResult<Self> {
79 match stream.peek()? {
80 ValueType::Null => {
81 stream.next_null()?;
82 return Ok(Self::null());
83 }
84 _ => stream.begin_object()?,
85 }
86
87 let mut id_type: Option<u16> = None;
88 let mut namespace: Option<u16> = None;
89 let mut value: Option<RawIdentifier> = None;
90
91 while stream.has_next()? {
92 match stream.next_name()? {
93 "IdType" => {
94 id_type = Some(stream.next_number()??);
95 }
96 "Namespace" => {
97 namespace = Some(stream.next_number()??);
98 }
99 "Id" => match stream.peek()? {
100 ValueType::Null => {
101 stream.next_null()?;
102 value = Some(RawIdentifier::Integer(0));
103 }
104 ValueType::Number => {
105 value = Some(RawIdentifier::Integer(stream.next_number()??));
106 }
107 _ => {
108 value = Some(RawIdentifier::String(stream.next_string()?));
109 }
110 },
111 _ => stream.skip_value()?,
112 }
113 }
114
115 let identifier = match id_type {
116 Some(1) => {
117 let Some(RawIdentifier::String(s)) = value else {
118 return Err(Error::decoding("Invalid NodeId, empty identifier"));
119 };
120 let s = UAString::from(s);
121 if s.is_null() || s.is_empty() {
122 return Err(Error::decoding("Invalid NodeId, empty identifier"));
123 }
124 Identifier::String(s)
125 }
126 Some(2) => {
127 let Some(RawIdentifier::String(s)) = value else {
128 return Err(Error::decoding("Invalid NodeId, empty identifier"));
129 };
130 if s.is_empty() {
131 return Err(Error::decoding("Invalid NodeId, empty identifier"));
132 }
133 let s = Guid::from_str(&s).map_err(|_| {
134 warn!("Unable to decode GUID identifier");
135 Error::decoding("Unable to decode GUID identifier")
136 })?;
137 Identifier::Guid(s)
138 }
139 Some(3) => {
140 let Some(RawIdentifier::String(s)) = value else {
141 return Err(Error::decoding("Invalid NodeId, empty identifier"));
142 };
143 if s.is_empty() {
144 return Err(Error::decoding("Invalid NodeId, empty identifier"));
145 }
146 let s: ByteString = ByteString::from_base64(&s)
147 .ok_or_else(|| Error::decoding("Unable to decode bytestring identifier"))?;
148 Identifier::ByteString(s)
149 }
150 None | Some(0) => {
151 let Some(RawIdentifier::Integer(s)) = value else {
152 return Err(Error::decoding("Invalid NodeId, empty identifier"));
153 };
154 Identifier::Numeric(s)
155 }
156 Some(r) => {
157 return Err(Error::decoding(format!(
158 "Failed to deserialize NodeId, got unexpected IdType {r}"
159 )));
160 }
161 };
162
163 stream.end_object()?;
164 Ok(Self {
165 namespace: namespace.unwrap_or_default(),
166 identifier,
167 })
168 }
169}