opcua_types/
argument.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5use std::io::{Read, Write};
6
7use crate::{
8    encoding::*, localized_text::LocalizedText, node_id::NodeId, status_codes::StatusCode,
9    string::UAString,
10};
11
12// From OPC UA Part 3 - Address Space Model 1.03 Specification
13//
14// This Structured DataType defines a Method input or output argument specification. It is for
15// example used in the input and output argument Properties for Methods. Its elements are described in
16// Table23
17
18#[derive(Clone, Debug, PartialEq)]
19pub struct Argument {
20    pub name: UAString,
21    pub data_type: NodeId,
22    pub value_rank: i32,
23    pub array_dimensions: Option<Vec<u32>>,
24    pub description: LocalizedText,
25}
26
27impl BinaryEncoder<Argument> for Argument {
28    fn byte_len(&self) -> usize {
29        let mut size = 0;
30        size += self.name.byte_len();
31        size += self.data_type.byte_len();
32        size += self.value_rank.byte_len();
33        size += byte_len_array(&self.array_dimensions);
34        size += self.description.byte_len();
35        size
36    }
37
38    fn encode<S: Write>(&self, stream: &mut S) -> EncodingResult<usize> {
39        let mut size = 0;
40        size += self.name.encode(stream)?;
41        size += self.data_type.encode(stream)?;
42        size += self.value_rank.encode(stream)?;
43        // Encode the array dimensions
44        if self.value_rank > 0 {
45            if let Some(ref array_dimensions) = self.array_dimensions {
46                if self.value_rank as usize != array_dimensions.len() {
47                    error!("The array dimensions {} of the Argument should match value rank {} and they don't", array_dimensions.len(), self.value_rank);
48                    return Err(StatusCode::BadDataEncodingInvalid);
49                }
50                size += write_array(stream, &self.array_dimensions)?;
51            } else {
52                error!("The array dimensions are expected in the Argument matching value rank {} and they aren't", self.value_rank);
53                return Err(StatusCode::BadDataEncodingInvalid);
54            }
55        } else {
56            size += write_u32(stream, 0u32)?;
57        }
58
59        size += self.description.encode(stream)?;
60        Ok(size)
61    }
62
63    fn decode<S: Read>(stream: &mut S, decoding_options: &DecodingOptions) -> EncodingResult<Self> {
64        let name = UAString::decode(stream, decoding_options)?;
65        let data_type = NodeId::decode(stream, decoding_options)?;
66        let value_rank = i32::decode(stream, decoding_options)?;
67        // Decode array dimensions
68        let array_dimensions: Option<Vec<u32>> = read_array(stream, decoding_options)?;
69        if let Some(ref array_dimensions) = array_dimensions {
70            if value_rank > 0 && value_rank as usize != array_dimensions.len() {
71                error!("The array dimensions {} of the Argument should match value rank {} and they don't", array_dimensions.len(), value_rank);
72                return Err(StatusCode::BadDataEncodingInvalid);
73            }
74        }
75        let description = LocalizedText::decode(stream, decoding_options)?;
76        Ok(Argument {
77            name,
78            data_type,
79            value_rank,
80            array_dimensions,
81            description,
82        })
83    }
84}