Skip to main content

opcua_types/
array.rs

1use crate::variant::*;
2use crate::StatusCode;
3
4/// An array is a vector of values with an optional number of dimensions.
5/// It is expected that the multi-dimensional array is valid, or it might not be encoded or decoded
6/// properly. The dimensions should match the number of values, or the array is invalid.
7#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
8pub struct Array {
9    // Type of elements in the array
10    pub value_type: VariantTypeId,
11
12    /// Values are stored sequentially
13    pub values: Vec<Variant>,
14
15    /// Multi dimension array which can contain any scalar type, all the same type. Nested
16    /// arrays are rejected. Higher rank dimensions are serialized first. For example an array
17    /// with dimensions [2,2,2] is written in this order - [0,0,0], [0,0,1], [0,1,0], [0,1,1],
18    /// [1,0,0], [1,0,1], [1,1,0], [1,1,1].
19    pub dimensions: Vec<u32>,
20}
21
22impl Array {
23    pub fn new_single<V>(value_type: VariantTypeId, values: V) -> Result<Array, StatusCode>
24    where
25        V: Into<Vec<Variant>>,
26    {
27        let values = values.into();
28        if Self::validate_array_type_to_values(value_type, &values) {
29            Ok(Array {
30                value_type,
31                values,
32                dimensions: Vec::new(),
33            })
34        } else {
35            Err(StatusCode::BadDecodingError)
36        }
37    }
38
39    pub fn new_multi<V, D>(
40        value_type: VariantTypeId,
41        values: V,
42        dimensions: D,
43    ) -> Result<Array, StatusCode>
44    where
45        V: Into<Vec<Variant>>,
46        D: Into<Vec<u32>>,
47    {
48        let values = values.into();
49        if Self::validate_array_type_to_values(value_type, &values) {
50            Ok(Array {
51                value_type,
52                values,
53                dimensions: dimensions.into(),
54            })
55        } else {
56            Err(StatusCode::BadDecodingError)
57        }
58    }
59
60    /// This is a runtime check to ensure the type of the array also matches the types of the variants in the array.
61    fn validate_array_type_to_values(value_type: VariantTypeId, values: &[Variant]) -> bool {
62        match value_type {
63            VariantTypeId::Array | VariantTypeId::Empty => {
64                error!("Invalid array type supplied");
65                false
66            }
67            _ => {
68                if !values_are_of_type(values, value_type) {
69                    // If the values exist, then validate them to the type
70                    error!("Value type of array does not match contents");
71                    false
72                } else {
73                    true
74                }
75            }
76        }
77    }
78
79    pub fn is_valid(&self) -> bool {
80        self.is_valid_dimensions() && Self::array_is_valid(&self.values)
81    }
82
83    pub fn has_dimensions(&self) -> bool {
84        !self.dimensions.is_empty()
85    }
86
87    pub fn encoding_mask(&self) -> u8 {
88        let mut encoding_mask = self.value_type.encoding_mask();
89        encoding_mask |= EncodingMask::ARRAY_VALUES_BIT;
90        if self.has_dimensions() {
91            encoding_mask |= EncodingMask::ARRAY_DIMENSIONS_BIT;
92        }
93        encoding_mask
94    }
95
96    /// Tests that the variants in the slice all have the same variant type
97    fn array_is_valid(values: &[Variant]) -> bool {
98        if values.is_empty() {
99            true
100        } else {
101            let expected_type_id = values[0].type_id();
102            if expected_type_id == VariantTypeId::Array {
103                // Nested arrays are explicitly NOT allowed
104                error!("Variant array contains nested array {:?}", expected_type_id);
105                false
106            } else if values.len() > 1 {
107                values_are_of_type(&values[1..], expected_type_id)
108            } else {
109                // Only contains 1 element
110                true
111            }
112        }
113    }
114
115    fn is_valid_dimensions(&self) -> bool {
116        // Check that the array dimensions match the length of the array
117        let mut length: usize = 1;
118        for d in &self.dimensions {
119            // Check for invalid dimensions
120            if *d == 0 {
121                // This dimension has no fixed size, so skip it
122                continue;
123            }
124            length *= *d as usize;
125        }
126        length <= self.values.len()
127    }
128}
129
130/// Check that all elements in the slice of arrays are the same type.
131pub fn values_are_of_type(values: &[Variant], expected_type: VariantTypeId) -> bool {
132    // Ensure all remaining elements are the same type as the first element
133    let found_unexpected = values.iter().any(|v| v.type_id() != expected_type);
134    if found_unexpected {
135        error!(
136            "Variant array's type is expected to be {:?} but found other types in it",
137            expected_type
138        );
139    };
140    !found_unexpected
141}