opcua_types/
diagnostic_info.rs1use std::io::{Read, Write};
8
9use crate::{
10 encoding::{BinaryDecodable, BinaryEncodable, EncodingResult},
11 status_code::StatusCode,
12 string::UAString,
13 write_i32, write_u8, Context,
14};
15use bitflags::bitflags;
16
17bitflags! {
18 #[derive(Copy, Clone, Debug, PartialEq, Default)]
20 pub struct DiagnosticInfoMask: u8 {
21 const HAS_SYMBOLIC_ID = 0x01;
23 const HAS_NAMESPACE = 0x02;
25 const HAS_LOCALIZED_TEXT = 0x04;
27 const HAS_LOCALE = 0x08;
29 const HAS_ADDITIONAL_INFO = 0x10;
31 const HAS_INNER_STATUS_CODE = 0x20;
33 const HAS_INNER_DIAGNOSTIC_INFO = 0x40;
35 }
36}
37
38bitflags! {
39 #[derive(Copy, Clone, Debug, PartialEq, Default)]
40 pub struct DiagnosticBits: u32 {
42 const SERVICE_LEVEL_SYMBOLIC_ID = 0x0000_0001;
44 const SERVICE_LEVEL_LOCALIZED_TEXT = 0x0000_0002;
46 const SERVICE_LEVEL_ADDITIONAL_INFO = 0x0000_0004;
48 const SERVICE_LEVEL_LOCALIZED_INNER_STATUS_CODE = 0x0000_0008;
50 const SERVICE_LEVEL_LOCALIZED_INNER_DIAGNOSTICS = 0x0000_0010;
52 const OPERATIONAL_LEVEL_SYMBOLIC_ID = 0x0000_0020;
54 const OPERATIONAL_LEVEL_LOCALIZED_TEXT = 0x0000_0040;
56 const OPERATIONAL_LEVEL_ADDITIONAL_INFO = 0x0000_0080;
58 const OPERATIONAL_LEVEL_INNER_STATUS_CODE = 0x0000_0100;
60 const OPERATIONAL_LEVEL_INNER_DIAGNOSTICS = 0x0000_0200;
62 }
63}
64
65impl crate::UaNullable for DiagnosticBits {
66 fn is_ua_null(&self) -> bool {
67 self.is_empty()
68 }
69}
70
71#[cfg(feature = "json")]
72mod json {
73 use crate::json::*;
74
75 use super::DiagnosticBits;
76
77 impl JsonEncodable for DiagnosticBits {
78 fn encode(
79 &self,
80 stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
81 _ctx: &crate::Context<'_>,
82 ) -> super::EncodingResult<()> {
83 stream.number_value(self.bits())?;
84 Ok(())
85 }
86 }
87
88 impl JsonDecodable for DiagnosticBits {
89 fn decode(
90 stream: &mut JsonStreamReader<&mut dyn std::io::Read>,
91 _ctx: &Context<'_>,
92 ) -> super::EncodingResult<Self> {
93 Ok(Self::from_bits_truncate(stream.next_number()??))
94 }
95 }
96}
97
98#[cfg(feature = "xml")]
99mod xml {
100 use crate::xml::*;
101 use std::io::{Read, Write};
102
103 use super::DiagnosticBits;
104
105 impl XmlType for DiagnosticBits {
106 const TAG: &'static str = u32::TAG;
107 }
108
109 impl XmlEncodable for DiagnosticBits {
110 fn encode(
111 &self,
112 writer: &mut XmlStreamWriter<&mut dyn Write>,
113 context: &Context<'_>,
114 ) -> EncodingResult<()> {
115 self.bits().encode(writer, context)
116 }
117 }
118
119 impl XmlDecodable for DiagnosticBits {
120 fn decode(
121 reader: &mut XmlStreamReader<&mut dyn Read>,
122 context: &Context<'_>,
123 ) -> EncodingResult<Self> {
124 let v = u32::decode(reader, context)?;
125 Ok(Self::from_bits_truncate(v))
126 }
127 }
128}
129
130#[allow(unused)]
131mod opcua {
132 pub(super) use crate as types;
133}
134
135#[derive(PartialEq, Debug, Clone, crate::UaNullable)]
137#[cfg_attr(
138 feature = "json",
139 derive(opcua_macros::JsonEncodable, opcua_macros::JsonDecodable)
140)]
141#[cfg_attr(
142 feature = "xml",
143 derive(crate::XmlEncodable, crate::XmlDecodable, crate::XmlType)
144)]
145pub struct DiagnosticInfo {
146 pub symbolic_id: Option<i32>,
148 pub namespace_uri: Option<i32>,
150 pub locale: Option<i32>,
152 pub localized_text: Option<i32>,
154 pub additional_info: Option<UAString>,
156 pub inner_status_code: Option<StatusCode>,
158 pub inner_diagnostic_info: Option<Box<DiagnosticInfo>>,
160}
161
162impl BinaryEncodable for DiagnosticInfo {
163 fn byte_len(&self, ctx: &opcua::types::Context<'_>) -> usize {
164 let mut size: usize = 0;
165 size += 1; if let Some(ref symbolic_id) = self.symbolic_id {
167 size += symbolic_id.byte_len(ctx);
169 }
170 if let Some(ref namespace_uri) = self.namespace_uri {
171 size += namespace_uri.byte_len(ctx)
173 }
174 if let Some(ref locale) = self.locale {
175 size += locale.byte_len(ctx)
177 }
178 if let Some(ref localized_text) = self.localized_text {
179 size += localized_text.byte_len(ctx)
181 }
182 if let Some(ref additional_info) = self.additional_info {
183 size += additional_info.byte_len(ctx)
185 }
186 if let Some(ref inner_status_code) = self.inner_status_code {
187 size += inner_status_code.byte_len(ctx)
189 }
190 if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
191 size += inner_diagnostic_info.byte_len(ctx)
193 }
194 size
195 }
196
197 fn encode<S: Write + ?Sized>(&self, stream: &mut S, ctx: &Context<'_>) -> EncodingResult<()> {
198 write_u8(stream, self.encoding_mask().bits())?;
199 if let Some(ref symbolic_id) = self.symbolic_id {
200 write_i32(stream, *symbolic_id)?;
202 }
203 if let Some(ref namespace_uri) = self.namespace_uri {
204 namespace_uri.encode(stream, ctx)?;
206 }
207 if let Some(ref locale) = self.locale {
208 locale.encode(stream, ctx)?;
210 }
211 if let Some(ref localized_text) = self.localized_text {
212 localized_text.encode(stream, ctx)?;
214 }
215 if let Some(ref additional_info) = self.additional_info {
216 additional_info.encode(stream, ctx)?;
218 }
219 if let Some(ref inner_status_code) = self.inner_status_code {
220 inner_status_code.encode(stream, ctx)?;
222 }
223 if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
224 inner_diagnostic_info.clone().encode(stream, ctx)?;
226 }
227 Ok(())
228 }
229}
230
231impl BinaryDecodable for DiagnosticInfo {
232 fn decode<S: Read + ?Sized>(stream: &mut S, ctx: &Context<'_>) -> EncodingResult<Self> {
233 let encoding_mask = DiagnosticInfoMask::from_bits_truncate(u8::decode(stream, ctx)?);
234 let mut diagnostic_info = DiagnosticInfo::default();
235
236 if encoding_mask.contains(DiagnosticInfoMask::HAS_SYMBOLIC_ID) {
237 diagnostic_info.symbolic_id = Some(i32::decode(stream, ctx)?);
239 }
240 if encoding_mask.contains(DiagnosticInfoMask::HAS_NAMESPACE) {
241 diagnostic_info.namespace_uri = Some(i32::decode(stream, ctx)?);
243 }
244 if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALE) {
245 diagnostic_info.locale = Some(i32::decode(stream, ctx)?);
247 }
248 if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALIZED_TEXT) {
249 diagnostic_info.localized_text = Some(i32::decode(stream, ctx)?);
251 }
252 if encoding_mask.contains(DiagnosticInfoMask::HAS_ADDITIONAL_INFO) {
253 diagnostic_info.additional_info = Some(UAString::decode(stream, ctx)?);
255 }
256 if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_STATUS_CODE) {
257 diagnostic_info.inner_status_code = Some(StatusCode::decode(stream, ctx)?);
259 }
260 if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO) {
261 diagnostic_info.inner_diagnostic_info =
263 Some(Box::new(DiagnosticInfo::decode(stream, ctx)?));
264 }
265 Ok(diagnostic_info)
266 }
267}
268
269impl Default for DiagnosticInfo {
270 fn default() -> Self {
271 DiagnosticInfo::null()
272 }
273}
274
275impl DiagnosticInfo {
276 pub fn null() -> DiagnosticInfo {
278 DiagnosticInfo {
279 symbolic_id: None,
280 namespace_uri: None,
281 locale: None,
282 localized_text: None,
283 additional_info: None,
284 inner_status_code: None,
285 inner_diagnostic_info: None,
286 }
287 }
288
289 pub fn encoding_mask(&self) -> DiagnosticInfoMask {
291 let mut encoding_mask = DiagnosticInfoMask::empty();
292 if self.symbolic_id.is_some() {
293 encoding_mask |= DiagnosticInfoMask::HAS_SYMBOLIC_ID;
294 }
295 if self.namespace_uri.is_some() {
296 encoding_mask |= DiagnosticInfoMask::HAS_NAMESPACE;
297 }
298 if self.locale.is_some() {
299 encoding_mask |= DiagnosticInfoMask::HAS_LOCALE;
300 }
301 if self.localized_text.is_some() {
302 encoding_mask |= DiagnosticInfoMask::HAS_LOCALIZED_TEXT;
303 }
304 if self.additional_info.is_some() {
305 encoding_mask |= DiagnosticInfoMask::HAS_ADDITIONAL_INFO;
306 }
307 if self.inner_status_code.is_some() {
308 encoding_mask |= DiagnosticInfoMask::HAS_INNER_STATUS_CODE;
309 }
310 if self.inner_diagnostic_info.is_some() {
311 encoding_mask |= DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO;
312 }
313 encoding_mask
314 }
315}