1use opcua_types::{
8 AttributeId, AttributesMask, DataEncoding, DataValue, NumericRange, StatusCode,
9 TimestampsToReturn, TryFromVariant, VariableTypeAttributes, Variant,
10};
11use tracing::error;
12
13use crate::FromAttributesError;
14
15use super::{base::Base, node::Node, node::NodeBase};
16
17node_builder_impl!(VariableTypeBuilder, VariableType);
18
19node_builder_impl_generates_event!(VariableTypeBuilder);
20node_builder_impl_subtype!(VariableTypeBuilder);
21
22impl VariableTypeBuilder {
23 pub fn is_abstract(mut self, is_abstract: bool) -> Self {
26 self.node.set_is_abstract(is_abstract);
27 self
28 }
29
30 pub fn write_mask(mut self, write_mask: WriteMask) -> Self {
32 self.node.set_write_mask(write_mask);
33 self
34 }
35
36 pub fn data_type(mut self, data_type: impl Into<NodeId>) -> Self {
38 self.node.set_data_type(data_type);
39 self
40 }
41
42 pub fn value(mut self, value: impl Into<Variant>) -> Self {
44 self.node.set_value(value);
45 self
46 }
47
48 pub fn array_dimensions(mut self, array_dimensions: &[u32]) -> Self {
50 self.node.set_array_dimensions(array_dimensions);
51 self
52 }
53
54 pub fn value_rank(mut self, value_rank: i32) -> Self {
56 self.node.set_value_rank(value_rank);
57 self
58 }
59}
60
61#[derive(Debug)]
63pub struct VariableType {
64 pub(super) base: Base,
65 pub(super) data_type: NodeId,
66 pub(super) is_abstract: bool,
67 pub(super) value_rank: i32,
68 pub(super) value: Option<DataValue>,
69 pub(super) array_dimensions: Option<Vec<u32>>,
70}
71
72impl Default for VariableType {
73 fn default() -> Self {
74 Self {
75 base: Base::new(NodeClass::VariableType, &NodeId::null(), "", ""),
76 data_type: NodeId::null(),
77 is_abstract: false,
78 value_rank: -1,
79 value: None,
80 array_dimensions: None,
81 }
82 }
83}
84
85node_base_impl!(VariableType);
86
87impl Node for VariableType {
88 fn get_attribute_max_age(
89 &self,
90 timestamps_to_return: TimestampsToReturn,
91 attribute_id: AttributeId,
92 index_range: &NumericRange,
93 data_encoding: &DataEncoding,
94 max_age: f64,
95 ) -> Option<DataValue> {
96 match attribute_id {
97 AttributeId::Value => self.value().cloned(),
98 AttributeId::DataType => Some(self.data_type().clone().into()),
99 AttributeId::IsAbstract => Some(self.is_abstract().into()),
100 AttributeId::ValueRank => Some(self.value_rank().into()),
101 AttributeId::ArrayDimensions => self.array_dimensions().map(DataValue::value_only),
103 _ => self.base.get_attribute_max_age(
104 timestamps_to_return,
105 attribute_id,
106 index_range,
107 data_encoding,
108 max_age,
109 ),
110 }
111 }
112
113 fn set_attribute(
114 &mut self,
115 attribute_id: AttributeId,
116 value: Variant,
117 ) -> Result<(), StatusCode> {
118 match attribute_id {
119 AttributeId::DataType => {
120 if let Variant::NodeId(v) = value {
121 self.set_data_type(*v);
122 Ok(())
123 } else {
124 Err(StatusCode::BadTypeMismatch)
125 }
126 }
127 AttributeId::IsAbstract => {
128 if let Variant::Boolean(v) = value {
129 self.set_is_abstract(v);
130 Ok(())
131 } else {
132 Err(StatusCode::BadTypeMismatch)
133 }
134 }
135 AttributeId::ValueRank => {
136 if let Variant::Int32(v) = value {
137 self.set_value_rank(v);
138 Ok(())
139 } else {
140 Err(StatusCode::BadTypeMismatch)
141 }
142 }
143 AttributeId::Value => {
144 self.set_value(value);
145 Ok(())
146 }
147 AttributeId::ArrayDimensions => {
148 let array_dimensions = <Vec<u32>>::try_from_variant(value);
149 if let Ok(array_dimensions) = array_dimensions {
150 self.set_array_dimensions(&array_dimensions);
151 Ok(())
152 } else {
153 Err(StatusCode::BadTypeMismatch)
154 }
155 }
156 _ => self.base.set_attribute(attribute_id, value),
157 }
158 }
159}
160
161impl VariableType {
162 pub fn new(
164 node_id: &NodeId,
165 browse_name: impl Into<QualifiedName>,
166 display_name: impl Into<LocalizedText>,
167 data_type: NodeId,
168 is_abstract: bool,
169 value_rank: i32,
170 ) -> VariableType {
171 VariableType {
172 base: Base::new(NodeClass::VariableType, node_id, browse_name, display_name),
173 data_type,
174 is_abstract,
175 value_rank,
176 value: None,
177 array_dimensions: None,
178 }
179 }
180
181 pub fn new_full(
184 base: Base,
185 data_type: NodeId,
186 is_abstract: bool,
187 value_rank: i32,
188 value: Option<DataValue>,
189 array_dimensions: Option<Vec<u32>>,
190 ) -> Self {
191 Self {
192 base,
193 data_type,
194 is_abstract,
195 value,
196 value_rank,
197 array_dimensions,
198 }
199 }
200
201 pub fn from_attributes(
203 node_id: &NodeId,
204 browse_name: impl Into<QualifiedName>,
205 attributes: VariableTypeAttributes,
206 ) -> Result<Self, FromAttributesError> {
207 let mandatory_attributes = AttributesMask::DISPLAY_NAME
208 | AttributesMask::IS_ABSTRACT
209 | AttributesMask::DATA_TYPE
210 | AttributesMask::VALUE_RANK;
211 let mask = AttributesMask::from_bits(attributes.specified_attributes)
212 .ok_or(FromAttributesError::InvalidMask)?;
213 if mask.contains(mandatory_attributes) {
214 let mut node = Self::new(
215 node_id,
216 browse_name,
217 attributes.display_name,
218 attributes.data_type,
219 attributes.is_abstract,
220 attributes.value_rank,
221 );
222 if mask.contains(AttributesMask::DESCRIPTION) {
223 node.set_description(attributes.description);
224 }
225 if mask.contains(AttributesMask::WRITE_MASK) {
226 node.set_write_mask(WriteMask::from_bits_truncate(attributes.write_mask));
227 }
228 if mask.contains(AttributesMask::USER_WRITE_MASK) {
229 node.set_user_write_mask(WriteMask::from_bits_truncate(attributes.user_write_mask));
230 }
231 if mask.contains(AttributesMask::VALUE) {
232 node.set_value(attributes.value);
233 }
234 if mask.contains(AttributesMask::ARRAY_DIMENSIONS) {
235 node.set_array_dimensions(attributes.array_dimensions.unwrap().as_slice());
236 }
237 Ok(node)
238 } else {
239 error!("VariableType cannot be created from attributes - missing mandatory values");
240 Err(FromAttributesError::MissingMandatoryValues)
241 }
242 }
243
244 pub fn is_valid(&self) -> bool {
246 self.base.is_valid()
247 }
248
249 pub fn data_type(&self) -> &NodeId {
251 &self.data_type
252 }
253
254 pub fn set_data_type(&mut self, data_type: impl Into<NodeId>) {
256 self.data_type = data_type.into();
257 }
258
259 pub fn is_abstract(&self) -> bool {
261 self.is_abstract
262 }
263
264 pub fn set_is_abstract(&mut self, is_abstract: bool) {
266 self.is_abstract = is_abstract;
267 }
268
269 pub fn value_rank(&self) -> i32 {
271 self.value_rank
272 }
273
274 pub fn set_value_rank(&mut self, value_rank: i32) {
276 self.value_rank = value_rank;
277 }
278
279 pub fn array_dimensions(&self) -> Option<Vec<u32>> {
281 self.array_dimensions.clone()
282 }
283
284 pub fn set_array_dimensions(&mut self, array_dimensions: &[u32]) {
286 self.array_dimensions = Some(array_dimensions.to_vec());
287 }
288
289 pub fn value(&self) -> Option<&DataValue> {
291 self.value.as_ref()
292 }
293
294 pub fn set_value(&mut self, value: impl Into<Variant>) {
296 self.value = Some(DataValue::new_now(value));
297 }
298
299 pub fn set_data_value(&mut self, value: DataValue) {
302 self.value = Some(value);
303 }
304}