opcua/types/
diagnostic_info.rs1use std::io::{Read, Write};
8
9use crate::types::{encoding::*, status_codes::StatusCode, string::UAString};
10
11bitflags! {
12 pub struct DiagnosticInfoMask: u8 {
13 const HAS_SYMBOLIC_ID = 0x01;
14 const HAS_NAMESPACE = 0x02;
15 const HAS_LOCALIZED_TEXT = 0x04;
16 const HAS_LOCALE = 0x08;
17 const HAS_ADDITIONAL_INFO = 0x10;
18 const HAS_INNER_STATUS_CODE = 0x20;
19 const HAS_INNER_DIAGNOSTIC_INFO = 0x40;
20 }
21}
22
23bitflags! {
24 pub struct DiagnosticBits: u32 {
25 const SERVICE_LEVEL_SYMBOLIC_ID = 0x0000_0001;
27 const SERVICE_LEVEL_LOCALIZED_TEXT = 0x0000_0002;
29 const SERVICE_LEVEL_ADDITIONAL_INFO = 0x0000_0004;
31 const SERVICE_LEVEL_LOCALIZED_INNER_STATUS_CODE = 0x0000_0008;
33 const SERVICE_LEVEL_LOCALIZED_INNER_DIAGNOSTICS = 0x0000_0010;
35 const OPERATIONAL_LEVEL_SYMBOLIC_ID = 0x0000_0020;
37 const OPERATIONAL_LEVEL_LOCALIZED_TEXT = 0x0000_0040;
39 const OPERATIONAL_LEVEL_ADDITIONAL_INFO = 0x0000_0080;
41 const OPERATIONAL_LEVEL_INNER_STATUS_CODE = 0x0000_0100;
43 const OPERATIONAL_LEVEL_INNER_DIAGNOSTICS = 0x0000_0200;
45 }
46}
47
48#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
50#[serde(rename_all = "PascalCase")]
51pub struct DiagnosticInfo {
52 #[serde(skip_serializing_if = "Option::is_none")]
54 pub symbolic_id: Option<i32>,
55 #[serde(skip_serializing_if = "Option::is_none")]
57 pub namespace_uri: Option<i32>,
58 #[serde(skip_serializing_if = "Option::is_none")]
60 pub locale: Option<i32>,
61 #[serde(skip_serializing_if = "Option::is_none")]
63 pub localized_text: Option<i32>,
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub additional_info: Option<UAString>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub inner_status_code: Option<StatusCode>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub inner_diagnostic_info: Option<Box<DiagnosticInfo>>,
73}
74
75impl BinaryEncoder<DiagnosticInfo> for DiagnosticInfo {
76 fn byte_len(&self) -> usize {
77 let mut size: usize = 0;
78 size += 1; if let Some(ref symbolic_id) = self.symbolic_id {
80 size += symbolic_id.byte_len();
82 }
83 if let Some(ref namespace_uri) = self.namespace_uri {
84 size += namespace_uri.byte_len()
86 }
87 if let Some(ref locale) = self.locale {
88 size += locale.byte_len()
90 }
91 if let Some(ref localized_text) = self.localized_text {
92 size += localized_text.byte_len()
94 }
95 if let Some(ref additional_info) = self.additional_info {
96 size += additional_info.byte_len()
98 }
99 if let Some(ref inner_status_code) = self.inner_status_code {
100 size += inner_status_code.byte_len()
102 }
103 if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
104 size += inner_diagnostic_info.byte_len()
106 }
107 size
108 }
109
110 fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
111 let mut size: usize = 0;
112 size += write_u8(stream, self.encoding_mask().bits)?;
113 if let Some(ref symbolic_id) = self.symbolic_id {
114 size += write_i32(stream, *symbolic_id)?;
116 }
117 if let Some(ref namespace_uri) = self.namespace_uri {
118 size += namespace_uri.encode(stream)?;
120 }
121 if let Some(ref locale) = self.locale {
122 size += locale.encode(stream)?;
124 }
125 if let Some(ref localized_text) = self.localized_text {
126 size += localized_text.encode(stream)?;
128 }
129 if let Some(ref additional_info) = self.additional_info {
130 size += additional_info.encode(stream)?;
132 }
133 if let Some(ref inner_status_code) = self.inner_status_code {
134 size += inner_status_code.encode(stream)?;
136 }
137 if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
138 size += inner_diagnostic_info.clone().encode(stream)?;
140 }
141 Ok(size)
142 }
143
144 fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
145 let encoding_mask =
146 DiagnosticInfoMask::from_bits_truncate(u8::decode(stream, decoding_options)?);
147 let mut diagnostic_info = DiagnosticInfo::default();
148
149 if encoding_mask.contains(DiagnosticInfoMask::HAS_SYMBOLIC_ID) {
150 diagnostic_info.symbolic_id = Some(i32::decode(stream, decoding_options)?);
152 }
153 if encoding_mask.contains(DiagnosticInfoMask::HAS_NAMESPACE) {
154 diagnostic_info.namespace_uri = Some(i32::decode(stream, decoding_options)?);
156 }
157 if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALE) {
158 diagnostic_info.locale = Some(i32::decode(stream, decoding_options)?);
160 }
161 if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALIZED_TEXT) {
162 diagnostic_info.localized_text = Some(i32::decode(stream, decoding_options)?);
164 }
165 if encoding_mask.contains(DiagnosticInfoMask::HAS_ADDITIONAL_INFO) {
166 diagnostic_info.additional_info = Some(UAString::decode(stream, decoding_options)?);
168 }
169 if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_STATUS_CODE) {
170 diagnostic_info.inner_status_code = Some(StatusCode::decode(stream, decoding_options)?);
172 }
173 if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO) {
174 diagnostic_info.inner_diagnostic_info =
176 Some(Box::new(DiagnosticInfo::decode(stream, decoding_options)?));
177 }
178 Ok(diagnostic_info)
179 }
180}
181
182impl Default for DiagnosticInfo {
183 fn default() -> Self {
184 DiagnosticInfo::null()
185 }
186}
187
188impl DiagnosticInfo {
189 pub fn null() -> DiagnosticInfo {
190 DiagnosticInfo {
191 symbolic_id: None,
192 namespace_uri: None,
193 locale: None,
194 localized_text: None,
195 additional_info: None,
196 inner_status_code: None,
197 inner_diagnostic_info: None,
198 }
199 }
200
201 pub fn encoding_mask(&self) -> DiagnosticInfoMask {
202 let mut encoding_mask = DiagnosticInfoMask::empty();
203 if self.symbolic_id.is_some() {
204 encoding_mask |= DiagnosticInfoMask::HAS_SYMBOLIC_ID;
205 }
206 if self.namespace_uri.is_some() {
207 encoding_mask |= DiagnosticInfoMask::HAS_NAMESPACE;
208 }
209 if self.locale.is_some() {
210 encoding_mask |= DiagnosticInfoMask::HAS_LOCALE;
211 }
212 if self.localized_text.is_some() {
213 encoding_mask |= DiagnosticInfoMask::HAS_LOCALIZED_TEXT;
214 }
215 if self.additional_info.is_some() {
216 encoding_mask |= DiagnosticInfoMask::HAS_ADDITIONAL_INFO;
217 }
218 if self.inner_status_code.is_some() {
219 encoding_mask |= DiagnosticInfoMask::HAS_INNER_STATUS_CODE;
220 }
221 if self.inner_diagnostic_info.is_some() {
222 encoding_mask |= DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO;
223 }
224 encoding_mask
225 }
226}