opcua_types/
argument.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2024 Adam Lock
4
5//! The [`Argument`] type, used for input and output arguments of methods.
6//!
7//! OPC UA Part 3, 8.6:
8//!
9//! This Structured DataType defines a Method input or output argument specification.
10//! It is for example used in the input and output argument Properties for Methods.
11//! Its elements are described in Table 28.
12
13use std::io::{Read, Write};
14
15use crate::{
16    encoding::{BinaryDecodable, BinaryEncodable, EncodingResult},
17    localized_text::LocalizedText,
18    node_id::NodeId,
19    string::UAString,
20    write_u32, Context, DataTypeId, Error, MessageInfo, ObjectId,
21};
22
23// From OPC UA Part 3 - Address Space Model 1.03 Specification
24//
25// This Structured DataType defines a Method input or output argument specification. It is for
26// example used in the input and output argument Properties for Methods. Its elements are described in
27// Table23
28
29#[allow(unused)]
30mod opcua {
31    pub(super) use crate as types;
32}
33
34#[derive(Clone, Debug, PartialEq, Default, crate::UaNullable)]
35#[cfg_attr(feature = "json", derive(crate::JsonEncodable, crate::JsonDecodable))]
36#[cfg_attr(
37    feature = "xml",
38    derive(crate::XmlEncodable, crate::XmlDecodable, crate::XmlType)
39)]
40/// OPC-UA method argument.
41pub struct Argument {
42    /// Argument name.
43    pub name: UAString,
44    /// Node ID of the argument data type.
45    pub data_type: NodeId,
46    /// Argument value rank.
47    pub value_rank: i32,
48    /// Argument array dimensions.
49    pub array_dimensions: Option<Vec<u32>>,
50    /// Argument description.
51    pub description: LocalizedText,
52}
53
54impl MessageInfo for Argument {
55    fn type_id(&self) -> ObjectId {
56        ObjectId::Argument_Encoding_DefaultBinary
57    }
58    fn json_type_id(&self) -> ObjectId {
59        ObjectId::Argument_Encoding_DefaultJson
60    }
61    fn xml_type_id(&self) -> ObjectId {
62        ObjectId::Argument_Encoding_DefaultXml
63    }
64    fn data_type_id(&self) -> crate::DataTypeId {
65        DataTypeId::Argument
66    }
67}
68
69impl BinaryEncodable for Argument {
70    fn byte_len(&self, ctx: &crate::Context<'_>) -> usize {
71        let mut size = 0;
72        size += self.name.byte_len(ctx);
73        size += self.data_type.byte_len(ctx);
74        size += self.value_rank.byte_len(ctx);
75        size += self.array_dimensions.byte_len(ctx);
76        size += self.description.byte_len(ctx);
77        size
78    }
79
80    fn encode<S: Write + ?Sized>(&self, stream: &mut S, ctx: &Context<'_>) -> EncodingResult<()> {
81        self.name.encode(stream, ctx)?;
82        self.data_type.encode(stream, ctx)?;
83        self.value_rank.encode(stream, ctx)?;
84        // Encode the array dimensions
85        if self.value_rank > 0 {
86            if let Some(ref array_dimensions) = self.array_dimensions {
87                if self.value_rank as usize != array_dimensions.len() {
88                    return Err(Error::encoding(
89                        format!("The array dimensions {} of the Argument should match value rank {} and they don't", array_dimensions.len(), self.value_rank)));
90                }
91                self.array_dimensions.encode(stream, ctx)?;
92            } else {
93                return Err(Error::encoding(format!("The array dimensions are expected in the Argument matching value rank {} and they aren't", self.value_rank)));
94            }
95        } else {
96            write_u32(stream, 0u32)?;
97        }
98
99        self.description.encode(stream, ctx)?;
100        Ok(())
101    }
102}
103
104impl BinaryDecodable for Argument {
105    fn decode<S: Read + ?Sized>(stream: &mut S, ctx: &Context<'_>) -> EncodingResult<Self> {
106        let name = UAString::decode(stream, ctx)?;
107        let data_type = NodeId::decode(stream, ctx)?;
108        let value_rank = i32::decode(stream, ctx)?;
109        // Decode array dimensions
110        let array_dimensions: Option<Vec<u32>> = BinaryDecodable::decode(stream, ctx)?;
111        if let Some(ref array_dimensions) = array_dimensions {
112            if value_rank > 0 && value_rank as usize != array_dimensions.len() {
113                return Err(Error::decoding(format!("The array dimensions {} of the Argument should match value rank {} and they don't", array_dimensions.len(), value_rank)));
114            }
115        }
116        let description = LocalizedText::decode(stream, ctx)?;
117        Ok(Argument {
118            name,
119            data_type,
120            value_rank,
121            array_dimensions,
122            description,
123        })
124    }
125}