Skip to content

Commit

Permalink
Support missing VariantTypes (locka99#171)
Browse files Browse the repository at this point in the history
Thanks I'll take it though a variant containing a variant seems weird. I'm assuming it's in the spec?
  • Loading branch information
schroeder- authored Feb 28, 2022
1 parent 3efa126 commit cfe95ea
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 4 deletions.
2 changes: 1 addition & 1 deletion types/src/diagnostic_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ bitflags! {
}

/// Diagnostic information.
#[derive(PartialEq, Debug, Clone)]
#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
pub struct DiagnosticInfo {
/// A symbolic name for the status code.
pub symbolic_id: Option<i32>,
Expand Down
24 changes: 24 additions & 0 deletions types/src/tests/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,6 +386,30 @@ fn variant() {
// ExtensionObject
let v = Variant::from(ExtensionObject::null());
serialize_test(v);
// DataValue Variant
let v = Variant::from(DataValue {
value: Some(Variant::Double(1000f64)),
status: Some(StatusCode::GoodClamped),
source_timestamp: Some(DateTime::now()),
source_picoseconds: Some(333),
server_timestamp: Some(DateTime::now()),
server_picoseconds: Some(666),
});
serialize_test(v);
// Variant in Variant
let v = Variant::Variant(Box::new(Variant::from(8u8)));
serialize_test(v);
// Diagnostic
let v = Variant::from(DiagnosticInfo {
symbolic_id: Some(99),
namespace_uri: Some(437437),
locale: Some(333),
localized_text: Some(233),
additional_info: Some(UAString::from("Nested diagnostic")),
inner_status_code: Some(StatusCode::Good),
inner_diagnostic_info: None,
});
serialize_test(v);
// DataValue
let v = DataValue {
value: Some(Variant::Double(1000f64)),
Expand Down
13 changes: 11 additions & 2 deletions types/src/tests/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ use crate::{
numeric_range::NumericRange,
status_code::StatusCode,
variant::{Variant, VariantTypeId},
ByteString, DataTypeId, DateTime, ExpandedNodeId, Guid, LocalizedText, NodeId, QualifiedName,
UAString,
ByteString, DataTypeId, DataValue, DateTime, DiagnosticInfo, ExpandedNodeId, Guid,
LocalizedText, NodeId, QualifiedName, UAString,
};

#[test]
Expand Down Expand Up @@ -83,6 +83,15 @@ fn variant_type_id() {
Variant::from(ExtensionObject::null()),
VariantTypeId::ExtensionObject,
),
(Variant::from(DataValue::null()), VariantTypeId::DataValue),
(
Variant::Variant(Box::new(Variant::from(32u8))),
VariantTypeId::Variant,
),
(
Variant::from(DiagnosticInfo::null()),
VariantTypeId::Diagnostic,
),
(Variant::from(vec![1]), VariantTypeId::Array),
];
for t in &types {
Expand Down
69 changes: 68 additions & 1 deletion types/src/variant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use crate::{
qualified_name::QualifiedName,
status_codes::StatusCode,
string::{UAString, XmlElement},
DataValue, DiagnosticInfo,
};

pub(crate) struct EncodingMask {}
Expand Down Expand Up @@ -54,7 +55,9 @@ impl EncodingMask {
pub const QUALIFIED_NAME: u8 = DataTypeId::QualifiedName as u8;
pub const LOCALIZED_TEXT: u8 = DataTypeId::LocalizedText as u8;
pub const EXTENSION_OBJECT: u8 = 22; // DataTypeId::ExtensionObject as u8;

pub const DATA_VALUE: u8 = DataTypeId::DataValue as u8;
pub const VARIANT: u8 = 24;
pub const DIAGNOSTIC: u8 = DataTypeId::DiagnosticInfo as u8;
/// Bit indicates an array with dimensions
pub const ARRAY_DIMENSIONS_BIT: u8 = 1 << 6;
/// Bit indicates an array with values
Expand Down Expand Up @@ -117,6 +120,12 @@ pub enum Variant {
ExpandedNodeId(Box<ExpandedNodeId>),
/// ExtensionObject
ExtensionObject(Box<ExtensionObject>),
// Variant
Variant(Box<Variant>),
// DataValue
DataValue(Box<DataValue>),
// Diagnostics
Diagnostics(Box<DiagnosticInfo>),
/// Single dimension array which can contain any scalar type, all the same type. Nested
/// arrays will be rejected.
Array(Box<Array>),
Expand Down Expand Up @@ -150,6 +159,9 @@ pub enum VariantTypeId {
NodeId,
ExpandedNodeId,
ExtensionObject,
Variant,
DataValue,
Diagnostic,
Array,
}

Expand Down Expand Up @@ -196,6 +208,15 @@ impl TryFrom<&NodeId> for VariantTypeId {
type_id if type_id == DataTypeId::LocalizedText as u32 => {
Ok(VariantTypeId::LocalizedText)
}
type_id if type_id == DataTypeId::DataValue as u32 => {
Ok(VariantTypeId::DataValue)
}
type_id if type_id == DataTypeId::BaseDataType as u32 => {
Ok(VariantTypeId::Variant)
}
type_id if type_id == DataTypeId::DiagnosticInfo as u32 => {
Ok(VariantTypeId::Diagnostic)
}
_ => Err(()),
}
} else {
Expand Down Expand Up @@ -235,6 +256,9 @@ impl VariantTypeId {
VariantTypeId::NodeId => EncodingMask::NODE_ID,
VariantTypeId::ExpandedNodeId => EncodingMask::EXPANDED_NODE_ID,
VariantTypeId::ExtensionObject => EncodingMask::EXTENSION_OBJECT,
VariantTypeId::Variant => EncodingMask::VARIANT,
VariantTypeId::DataValue => EncodingMask::DATA_VALUE,
VariantTypeId::Diagnostic => EncodingMask::DIAGNOSTIC,
VariantTypeId::Array => panic!("Type of array is unknown"),
}
}
Expand Down Expand Up @@ -264,6 +288,9 @@ impl VariantTypeId {
EncodingMask::NODE_ID => Ok(VariantTypeId::NodeId),
EncodingMask::EXPANDED_NODE_ID => Ok(VariantTypeId::ExpandedNodeId),
EncodingMask::EXTENSION_OBJECT => Ok(VariantTypeId::ExtensionObject),
EncodingMask::VARIANT => Ok(VariantTypeId::Variant),
EncodingMask::DATA_VALUE => Ok(VariantTypeId::DataValue),
EncodingMask::DIAGNOSTIC => Ok(VariantTypeId::Diagnostic),
_ => {
error!("Unrecognized encoding mask");
Err(StatusCode::BadDecodingError)
Expand Down Expand Up @@ -460,6 +487,18 @@ impl From<ExtensionObject> for Variant {
}
}

impl From<DataValue> for Variant {
fn from(v: DataValue) -> Self {
Variant::DataValue(Box::new(v))
}
}

impl From<DiagnosticInfo> for Variant {
fn from(v: DiagnosticInfo) -> Self {
Variant::Diagnostics(Box::new(v))
}
}

impl<'a, 'b> From<(VariantTypeId, &'a [&'b str])> for Variant {
fn from(v: (VariantTypeId, &'a [&'b str])) -> Self {
let values: Vec<Variant> = v.1.iter().map(|v| Variant::from(*v)).collect();
Expand Down Expand Up @@ -642,6 +681,9 @@ impl BinaryEncoder<Variant> for Variant {
Variant::QualifiedName(value) => value.byte_len(),
Variant::LocalizedText(value) => value.byte_len(),
Variant::ExtensionObject(value) => value.byte_len(),
Variant::DataValue(value) => value.byte_len(),
Variant::Variant(value) => value.byte_len(),
Variant::Diagnostics(value) => value.byte_len(),
Variant::Array(array) => {
// Array length
let mut size = 4;
Expand Down Expand Up @@ -692,6 +734,9 @@ impl BinaryEncoder<Variant> for Variant {
Variant::QualifiedName(value) => value.encode(stream)?,
Variant::LocalizedText(value) => value.encode(stream)?,
Variant::ExtensionObject(value) => value.encode(stream)?,
Variant::DataValue(value) => value.encode(stream)?,
Variant::Variant(value) => value.encode(stream)?,
Variant::Diagnostics(value) => value.encode(stream)?,
Variant::Array(array) => {
let mut size = write_i32(stream, array.values.len() as i32)?;
for value in array.values.iter() {
Expand Down Expand Up @@ -832,6 +877,7 @@ impl fmt::Display for Variant {
Variant::DateTime(ref v) => write!(f, "{}", v.to_string()),
Variant::NodeId(ref v) => write!(f, "{}", v.to_string()),
Variant::ExpandedNodeId(ref v) => write!(f, "{}", v.to_string()),
Variant::Variant(ref v) => write!(f, "Variant({})", v),
value => write!(f, "{:?}", value),
}
}
Expand Down Expand Up @@ -869,6 +915,9 @@ impl Variant {
Variant::QualifiedName(value) => value.byte_len(),
Variant::LocalizedText(value) => value.byte_len(),
Variant::ExtensionObject(value) => value.byte_len(),
Variant::Variant(value) => value.byte_len(),
Variant::DataValue(value) => value.byte_len(),
Variant::Diagnostics(value) => value.byte_len(),
_ => {
error!("Cannot compute length of this type (probably nested array)");
0
Expand Down Expand Up @@ -902,6 +951,9 @@ impl Variant {
Variant::QualifiedName(value) => value.encode(stream),
Variant::LocalizedText(value) => value.encode(stream),
Variant::ExtensionObject(value) => value.encode(stream),
Variant::Variant(value) => value.encode(stream),
Variant::DataValue(value) => value.encode(stream),
Variant::Diagnostics(value) => value.encode(stream),
_ => {
warn!("Cannot encode this variant value type (probably nested array)");
Err(StatusCode::BadEncodingError)
Expand Down Expand Up @@ -962,6 +1014,12 @@ impl Variant {
Self::from(LocalizedText::decode(stream, decoding_options)?)
} else if Self::test_encoding_flag(encoding_mask, EncodingMask::EXTENSION_OBJECT) {
Self::from(ExtensionObject::decode(stream, decoding_options)?)
} else if Self::test_encoding_flag(encoding_mask, EncodingMask::VARIANT) {
Variant::Variant(Box::new(Variant::decode(stream, decoding_options)?))
} else if Self::test_encoding_flag(encoding_mask, EncodingMask::DATA_VALUE) {
Self::from(DataValue::decode(stream, decoding_options)?)
} else if Self::test_encoding_flag(encoding_mask, EncodingMask::DIAGNOSTIC) {
Self::from(DiagnosticInfo::decode(stream, decoding_options)?)
} else {
Variant::Empty
};
Expand Down Expand Up @@ -1449,6 +1507,9 @@ impl Variant {
Variant::QualifiedName(_) => VariantTypeId::QualifiedName,
Variant::LocalizedText(_) => VariantTypeId::LocalizedText,
Variant::ExtensionObject(_) => VariantTypeId::ExtensionObject,
Variant::Variant(_) => VariantTypeId::Variant,
Variant::DataValue(_) => VariantTypeId::DataValue,
Variant::Diagnostics(_) => VariantTypeId::Diagnostic,
Variant::Array(_) => VariantTypeId::Array,
}
}
Expand Down Expand Up @@ -1556,6 +1617,9 @@ impl Variant {
Variant::StatusCode(_) => Some(DataTypeId::StatusCode.into()),
Variant::QualifiedName(_) => Some(DataTypeId::QualifiedName.into()),
Variant::LocalizedText(_) => Some(DataTypeId::LocalizedText.into()),
Variant::Variant(_) => Some(DataTypeId::BaseDataType.into()),
Variant::DataValue(_) => Some(DataTypeId::DataValue.into()),
Variant::Diagnostics(_) => Some(DataTypeId::DiagnosticInfo.into()),
_ => None,
}
}
Expand Down Expand Up @@ -1586,6 +1650,9 @@ impl Variant {
Variant::QualifiedName(_) => EncodingMask::QUALIFIED_NAME,
Variant::LocalizedText(_) => EncodingMask::LOCALIZED_TEXT,
Variant::ExtensionObject(_) => EncodingMask::EXTENSION_OBJECT,
Variant::Variant(_) => EncodingMask::VARIANT,
Variant::DataValue(_) => EncodingMask::DATA_VALUE,
Variant::Diagnostics(_) => EncodingMask::DIAGNOSTIC,
Variant::Array(array) => array.encoding_mask(),
}
}
Expand Down

0 comments on commit cfe95ea

Please sign in to comment.