use std::io::{Read, Write};
use crate::{
encoding::{BinaryDecodable, BinaryEncodable, EncodingResult},
status_code::StatusCode,
string::UAString,
write_i32, write_u8, Context,
};
use bitflags::bitflags;
bitflags! {
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub struct DiagnosticInfoMask: u8 {
const HAS_SYMBOLIC_ID = 0x01;
const HAS_NAMESPACE = 0x02;
const HAS_LOCALIZED_TEXT = 0x04;
const HAS_LOCALE = 0x08;
const HAS_ADDITIONAL_INFO = 0x10;
const HAS_INNER_STATUS_CODE = 0x20;
const HAS_INNER_DIAGNOSTIC_INFO = 0x40;
}
}
bitflags! {
#[derive(Copy, Clone, Debug, PartialEq, Default)]
pub struct DiagnosticBits: u32 {
const SERVICE_LEVEL_SYMBOLIC_ID = 0x0000_0001;
const SERVICE_LEVEL_LOCALIZED_TEXT = 0x0000_0002;
const SERVICE_LEVEL_ADDITIONAL_INFO = 0x0000_0004;
const SERVICE_LEVEL_LOCALIZED_INNER_STATUS_CODE = 0x0000_0008;
const SERVICE_LEVEL_LOCALIZED_INNER_DIAGNOSTICS = 0x0000_0010;
const OPERATIONAL_LEVEL_SYMBOLIC_ID = 0x0000_0020;
const OPERATIONAL_LEVEL_LOCALIZED_TEXT = 0x0000_0040;
const OPERATIONAL_LEVEL_ADDITIONAL_INFO = 0x0000_0080;
const OPERATIONAL_LEVEL_INNER_STATUS_CODE = 0x0000_0100;
const OPERATIONAL_LEVEL_INNER_DIAGNOSTICS = 0x0000_0200;
}
}
impl crate::UaNullable for DiagnosticBits {
fn is_ua_null(&self) -> bool {
self.is_empty()
}
}
#[cfg(feature = "json")]
mod json {
use crate::json::*;
use super::DiagnosticBits;
impl JsonEncodable for DiagnosticBits {
fn encode(
&self,
stream: &mut JsonStreamWriter<&mut dyn std::io::Write>,
_ctx: &crate::Context<'_>,
) -> super::EncodingResult<()> {
stream.number_value(self.bits())?;
Ok(())
}
}
impl JsonDecodable for DiagnosticBits {
fn decode(
stream: &mut JsonStreamReader<&mut dyn std::io::Read>,
_ctx: &Context<'_>,
) -> super::EncodingResult<Self> {
Ok(Self::from_bits_truncate(stream.next_number()??))
}
}
}
#[cfg(feature = "xml")]
mod xml {
use crate::xml::*;
use std::io::{Read, Write};
use super::DiagnosticBits;
impl XmlType for DiagnosticBits {
const TAG: &'static str = u32::TAG;
}
impl XmlEncodable for DiagnosticBits {
fn encode(
&self,
writer: &mut XmlStreamWriter<&mut dyn Write>,
context: &Context<'_>,
) -> EncodingResult<()> {
self.bits().encode(writer, context)
}
}
impl XmlDecodable for DiagnosticBits {
fn decode(
reader: &mut XmlStreamReader<&mut dyn Read>,
context: &Context<'_>,
) -> EncodingResult<Self> {
let v = u32::decode(reader, context)?;
Ok(Self::from_bits_truncate(v))
}
}
}
#[allow(unused)]
mod opcua {
pub(super) use crate as types;
}
#[derive(PartialEq, Debug, Clone, crate::UaNullable)]
#[cfg_attr(
feature = "json",
derive(opcua_macros::JsonEncodable, opcua_macros::JsonDecodable)
)]
#[cfg_attr(
feature = "xml",
derive(crate::XmlEncodable, crate::XmlDecodable, crate::XmlType)
)]
pub struct DiagnosticInfo {
pub symbolic_id: Option<i32>,
pub namespace_uri: Option<i32>,
pub locale: Option<i32>,
pub localized_text: Option<i32>,
pub additional_info: Option<UAString>,
pub inner_status_code: Option<StatusCode>,
pub inner_diagnostic_info: Option<Box<DiagnosticInfo>>,
}
impl BinaryEncodable for DiagnosticInfo {
fn byte_len(&self, ctx: &opcua::types::Context<'_>) -> usize {
let mut size: usize = 0;
size += 1; if let Some(ref symbolic_id) = self.symbolic_id {
size += symbolic_id.byte_len(ctx);
}
if let Some(ref namespace_uri) = self.namespace_uri {
size += namespace_uri.byte_len(ctx)
}
if let Some(ref locale) = self.locale {
size += locale.byte_len(ctx)
}
if let Some(ref localized_text) = self.localized_text {
size += localized_text.byte_len(ctx)
}
if let Some(ref additional_info) = self.additional_info {
size += additional_info.byte_len(ctx)
}
if let Some(ref inner_status_code) = self.inner_status_code {
size += inner_status_code.byte_len(ctx)
}
if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
size += inner_diagnostic_info.byte_len(ctx)
}
size
}
fn encode<S: Write + ?Sized>(&self, stream: &mut S, ctx: &Context<'_>) -> EncodingResult<()> {
write_u8(stream, self.encoding_mask().bits())?;
if let Some(ref symbolic_id) = self.symbolic_id {
write_i32(stream, *symbolic_id)?;
}
if let Some(ref namespace_uri) = self.namespace_uri {
namespace_uri.encode(stream, ctx)?;
}
if let Some(ref locale) = self.locale {
locale.encode(stream, ctx)?;
}
if let Some(ref localized_text) = self.localized_text {
localized_text.encode(stream, ctx)?;
}
if let Some(ref additional_info) = self.additional_info {
additional_info.encode(stream, ctx)?;
}
if let Some(ref inner_status_code) = self.inner_status_code {
inner_status_code.encode(stream, ctx)?;
}
if let Some(ref inner_diagnostic_info) = self.inner_diagnostic_info {
inner_diagnostic_info.clone().encode(stream, ctx)?;
}
Ok(())
}
}
impl BinaryDecodable for DiagnosticInfo {
fn decode<S: Read + ?Sized>(stream: &mut S, ctx: &Context<'_>) -> EncodingResult<Self> {
let encoding_mask = DiagnosticInfoMask::from_bits_truncate(u8::decode(stream, ctx)?);
let mut diagnostic_info = DiagnosticInfo::default();
if encoding_mask.contains(DiagnosticInfoMask::HAS_SYMBOLIC_ID) {
diagnostic_info.symbolic_id = Some(i32::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_NAMESPACE) {
diagnostic_info.namespace_uri = Some(i32::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALE) {
diagnostic_info.locale = Some(i32::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_LOCALIZED_TEXT) {
diagnostic_info.localized_text = Some(i32::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_ADDITIONAL_INFO) {
diagnostic_info.additional_info = Some(UAString::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_STATUS_CODE) {
diagnostic_info.inner_status_code = Some(StatusCode::decode(stream, ctx)?);
}
if encoding_mask.contains(DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO) {
diagnostic_info.inner_diagnostic_info =
Some(Box::new(DiagnosticInfo::decode(stream, ctx)?));
}
Ok(diagnostic_info)
}
}
impl Default for DiagnosticInfo {
fn default() -> Self {
DiagnosticInfo::null()
}
}
impl DiagnosticInfo {
pub fn null() -> DiagnosticInfo {
DiagnosticInfo {
symbolic_id: None,
namespace_uri: None,
locale: None,
localized_text: None,
additional_info: None,
inner_status_code: None,
inner_diagnostic_info: None,
}
}
pub fn encoding_mask(&self) -> DiagnosticInfoMask {
let mut encoding_mask = DiagnosticInfoMask::empty();
if self.symbolic_id.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_SYMBOLIC_ID;
}
if self.namespace_uri.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_NAMESPACE;
}
if self.locale.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_LOCALE;
}
if self.localized_text.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_LOCALIZED_TEXT;
}
if self.additional_info.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_ADDITIONAL_INFO;
}
if self.inner_status_code.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_INNER_STATUS_CODE;
}
if self.inner_diagnostic_info.is_some() {
encoding_mask |= DiagnosticInfoMask::HAS_INNER_DIAGNOSTIC_INFO;
}
encoding_mask
}
}