///|
/// OPC UA ExpandedNodeId with optional NamespaceUri and ServerIndex.
pub(all) struct ExpandedNodeId {
node_id : NodeId
namespace_uri : String?
server_index : UInt32?
}
///|
/// Construct an ExpandedNodeId without a URI or server index.
pub fn ExpandedNodeId::new(node_id : NodeId) -> ExpandedNodeId {
{ node_id, namespace_uri: None, server_index: None, }
}
///|
/// Add a NamespaceUri.
pub fn ExpandedNodeId::with_namespace_uri(
self : ExpandedNodeId,
namespace_uri : String,
) -> ExpandedNodeId {
{ ..self, namespace_uri: Some(namespace_uri), }
}
///|
/// Add a ServerIndex.
pub fn ExpandedNodeId::with_server_index(
self : ExpandedNodeId,
server_index : UInt32,
) -> ExpandedNodeId {
{ ..self, server_index: Some(server_index), }
}
///|
/// Render an ExpandedNodeId for diagnostics.
pub fn ExpandedNodeId::to_string(self : ExpandedNodeId) -> String {
let base = self.node_id.to_string()
let uri = match self.namespace_uri {
Some(value) => if value == "" { "" } else { "?uri=" + value }
None => ""
}
let server = match self.server_index {
Some(value) => if value == 0U { "" } else { "?server=" + value.to_string() }
None => ""
}
base + uri + server
}
///|
fn expanded_flags(
namespace_uri : String?,
server_index : UInt32?,
) -> (UInt32, Bool, Bool) {
let has_uri = match namespace_uri {
Some(value) => value != ""
None => false
}
let has_server = match server_index {
Some(value) => value != 0U
None => false
}
let flags = (if has_uri { 0x80U } else { 0U }) |
(if has_server { 0x40U } else { 0U })
(flags, has_uri, has_server)
}
///|
/// Encode an ExpandedNodeId.
pub fn UaWriter::write_expanded_node_id(
self : UaWriter,
value : ExpandedNodeId,
) -> Unit raise UaError {
let (flags, has_uri, has_server) = expanded_flags(
value.namespace_uri,
value.server_index,
)
let namespace_index = if has_uri {
0U.to_uint16()
} else {
value.node_id.namespace_index
}
match value.node_id.identifier {
Numeric(identifier) =>
if namespace_index.to_uint() <= 255U && identifier <= 255U {
self.write_u8(flags)
self.write_u8(namespace_index.to_uint())
self.write_u8(identifier)
} else if namespace_index.to_uint() <= 255U && identifier <= 65535U {
self.write_u8(flags | 0x01U)
self.write_u8(namespace_index.to_uint())
self.write_uint16(identifier.to_uint16())
} else {
self.write_u8(flags | 0x02U)
self.write_uint16(namespace_index)
self.write_uint32(identifier)
}
String(identifier) => {
self.write_u8(flags | 0x03U)
self.write_uint16(namespace_index)
self.write_string(identifier)
}
Guid(identifier) => {
if identifier.length() != 16 {
raise InvalidGuidLength(identifier.length())
}
self.write_u8(flags | 0x04U)
self.write_uint16(namespace_index)
self.buffer.write_bytes(identifier.exact_view())
}
Opaque(identifier) => {
self.write_u8(flags | 0x05U)
self.write_uint16(namespace_index)
self.write_bytes(identifier)
}
}
if has_uri {
match value.namespace_uri {
Some(uri) => self.write_string(uri)
None => ()
}
}
if has_server {
match value.server_index {
Some(index) => self.write_uint32(index)
None => ()
}
}
}
///|
/// Decode an ExpandedNodeId.
pub fn UaReader::read_expanded_node_id(
self : UaReader,
) -> ExpandedNodeId raise UaError {
let encoding = self.read_u8()
let has_uri = (encoding & 0x80U) != 0U
let has_server = (encoding & 0x40U) != 0U
let node_encoding = encoding & 0x3FU
let namespace_index = match node_encoding {
0 | 1 => self.read_u8().to_uint16()
2 | 3 | 4 | 5 => self.read_uint16()
other => raise InvalidNodeIdEncoding(other)
}
let identifier = match node_encoding {
0 => Numeric(self.read_u8())
1 => Numeric(self.read_uint16().to_uint())
2 => Numeric(self.read_uint32())
3 => String(self.read_required_string())
4 => Guid(self.take(16).to_owned())
5 => Opaque(self.read_required_bytes())
other => raise InvalidNodeIdEncoding(other)
}
let namespace_uri = if has_uri {
let uri = self.read_required_string()
if uri == "" {
raise InvalidValue("ExpandedNodeId NamespaceUri must not be empty")
}
Some(uri)
} else {
None
}
let server_index = if has_server {
let index = self.read_uint32()
if index == 0U {
raise InvalidValue("ExpandedNodeId ServerIndex must not be zero")
}
Some(index)
} else {
None
}
let effective_namespace = if has_uri {
0U.to_uint16()
} else {
namespace_index
}
{
node_id: { namespace_index: effective_namespace, identifier, },
namespace_uri,
server_index,
}
}