1use std::convert::Into;
8
9use opcua_types::{
10 AttributeId, AttributesMask, DataEncoding, DataTypeId, DataValue, DateTime, NumericRange,
11 StatusCode, TimestampsToReturn, TryFromVariant, VariableAttributes, Variant,
12};
13use tracing::error;
14
15use crate::FromAttributesError;
16
17use super::base::Base;
18use super::{AccessLevel, Node, NodeBase};
19
20node_builder_impl!(VariableBuilder, Variable);
23node_builder_impl_component_of!(VariableBuilder);
24node_builder_impl_property_of!(VariableBuilder);
25
26impl VariableBuilder {
27 pub fn value(mut self, value: impl Into<Variant>) -> Self {
29 let _ = self.node.set_value(&NumericRange::None, value);
30 self
31 }
32
33 pub fn data_type(mut self, data_type: impl Into<NodeId>) -> Self {
35 self.node.set_data_type(data_type);
36 self
37 }
38
39 pub fn historizing(mut self, historizing: bool) -> Self {
41 self.node.set_historizing(historizing);
42 self
43 }
44
45 pub fn access_level(mut self, access_level: AccessLevel) -> Self {
47 self.node.set_access_level(access_level);
48 self
49 }
50
51 pub fn user_access_level(mut self, user_access_level: AccessLevel) -> Self {
53 self.node.set_user_access_level(user_access_level);
54 self
55 }
56
57 pub fn value_rank(mut self, value_rank: i32) -> Self {
59 self.node.set_value_rank(value_rank);
60 self
61 }
62
63 pub fn array_dimensions(mut self, array_dimensions: &[u32]) -> Self {
65 self.node.set_array_dimensions(array_dimensions);
66 self
67 }
68
69 pub fn write_mask(mut self, write_mask: WriteMask) -> Self {
71 self.node.set_write_mask(write_mask);
72 self
73 }
74
75 pub fn writable(mut self) -> Self {
77 self.node
78 .set_user_access_level(self.node.user_access_level() | AccessLevel::CURRENT_WRITE);
79 self.node
80 .set_access_level(self.node.access_level() | AccessLevel::CURRENT_WRITE);
81 self
82 }
83
84 pub fn history_readable(mut self) -> Self {
86 self.node
87 .set_user_access_level(self.node.user_access_level() | AccessLevel::HISTORY_READ);
88 self.node
89 .set_access_level(self.node.access_level() | AccessLevel::HISTORY_READ);
90 self
91 }
92
93 pub fn history_updatable(mut self) -> Self {
95 self.node
96 .set_user_access_level(self.node.user_access_level() | AccessLevel::HISTORY_WRITE);
97 self.node
98 .set_access_level(self.node.access_level() | AccessLevel::HISTORY_WRITE);
99 self
100 }
101
102 pub fn minimum_sampling_interval(mut self, minimum_sampling_interval: f64) -> Self {
104 self.node
105 .set_minimum_sampling_interval(minimum_sampling_interval);
106 self
107 }
108
109 pub fn has_type_definition<T>(self, type_id: T) -> Self
111 where
112 T: Into<NodeId>,
113 {
114 self.reference(
115 type_id,
116 ReferenceTypeId::HasTypeDefinition,
117 ReferenceDirection::Forward,
118 )
119 }
120
121 pub fn has_modelling_rule<T>(self, type_id: T) -> Self
123 where
124 T: Into<NodeId>,
125 {
126 self.reference(
127 type_id,
128 ReferenceTypeId::HasModellingRule,
129 ReferenceDirection::Forward,
130 )
131 }
132}
133
134#[derive(Debug)]
138pub struct Variable {
139 pub(super) base: Base,
140 pub(super) data_type: NodeId,
141 pub(super) historizing: bool,
142 pub(super) value_rank: i32,
143 pub(super) value: DataValue,
144 pub(super) access_level: u8,
145 pub(super) user_access_level: u8,
146 pub(super) array_dimensions: Option<Vec<u32>>,
147 pub(super) minimum_sampling_interval: Option<f64>,
148}
149
150impl Default for Variable {
151 fn default() -> Self {
152 Self {
153 base: Base::new(NodeClass::Variable, &NodeId::null(), "", ""),
154 data_type: NodeId::null(),
155 historizing: false,
156 value_rank: -1,
157 value: Variant::Empty.into(),
158 access_level: AccessLevel::CURRENT_READ.bits(),
159 user_access_level: AccessLevel::CURRENT_READ.bits(),
160 array_dimensions: None,
161 minimum_sampling_interval: None,
162 }
163 }
164}
165
166node_base_impl!(Variable);
167
168impl Node for Variable {
169 fn get_attribute_max_age(
170 &self,
171 timestamps_to_return: TimestampsToReturn,
172 attribute_id: AttributeId,
173 index_range: &NumericRange,
174 data_encoding: &DataEncoding,
175 max_age: f64,
176 ) -> Option<DataValue> {
177 match attribute_id {
181 AttributeId::Value => {
183 Some(self.value(timestamps_to_return, index_range, data_encoding, max_age))
184 }
185 AttributeId::DataType => Some(self.data_type().into()),
186 AttributeId::Historizing => Some(self.historizing().into()),
187 AttributeId::ValueRank => Some(self.value_rank().into()),
188 AttributeId::AccessLevel => Some(self.access_level().bits().into()),
189 AttributeId::UserAccessLevel => Some(self.user_access_level().bits().into()),
190 AttributeId::ArrayDimensions => {
192 self.array_dimensions().map(|v| Variant::from(v).into())
193 }
194 AttributeId::MinimumSamplingInterval => {
195 self.minimum_sampling_interval().map(|v| v.into())
196 }
197 _ => self.base.get_attribute_max_age(
198 timestamps_to_return,
199 attribute_id,
200 index_range,
201 data_encoding,
202 max_age,
203 ),
204 }
205 }
206
207 fn set_attribute(
208 &mut self,
209 attribute_id: AttributeId,
210 value: Variant,
211 ) -> Result<(), StatusCode> {
212 match attribute_id {
213 AttributeId::DataType => {
214 if let Variant::NodeId(v) = value {
215 self.set_data_type(*v);
216 Ok(())
217 } else {
218 Err(StatusCode::BadTypeMismatch)
219 }
220 }
221 AttributeId::Historizing => {
222 if let Variant::Boolean(v) = value {
223 self.set_historizing(v);
224 Ok(())
225 } else {
226 Err(StatusCode::BadTypeMismatch)
227 }
228 }
229 AttributeId::ValueRank => {
230 if let Variant::Int32(v) = value {
231 self.set_value_rank(v);
232 Ok(())
233 } else {
234 Err(StatusCode::BadTypeMismatch)
235 }
236 }
237 AttributeId::Value => {
238 self.set_value(&NumericRange::None, value)
240 }
241 AttributeId::AccessLevel => {
242 if let Variant::Byte(v) = value {
243 self.set_access_level(AccessLevel::from_bits_truncate(v));
244 Ok(())
245 } else {
246 Err(StatusCode::BadTypeMismatch)
247 }
248 }
249 AttributeId::UserAccessLevel => {
250 if let Variant::Byte(v) = value {
251 self.set_user_access_level(AccessLevel::from_bits_truncate(v));
252 Ok(())
253 } else {
254 Err(StatusCode::BadTypeMismatch)
255 }
256 }
257 AttributeId::ArrayDimensions => {
258 let array_dimensions = <Vec<u32>>::try_from_variant(value);
259 if let Ok(array_dimensions) = array_dimensions {
260 self.set_array_dimensions(&array_dimensions);
261 Ok(())
262 } else {
263 Err(StatusCode::BadTypeMismatch)
264 }
265 }
266 AttributeId::MinimumSamplingInterval => {
267 if let Variant::Double(v) = value {
268 self.set_minimum_sampling_interval(v);
269 Ok(())
270 } else {
271 Err(StatusCode::BadTypeMismatch)
272 }
273 }
274 _ => self.base.set_attribute(attribute_id, value),
275 }
276 }
277}
278
279impl Variable {
280 pub fn new(
286 node_id: &NodeId,
287 browse_name: impl Into<QualifiedName>,
288 display_name: impl Into<LocalizedText>,
289 value: impl Into<Variant>,
290 ) -> Variable {
291 let value: Variant = value.into();
292 let data_type = value.data_type().or_else(|| value.data_type());
293 if let Some(data_type) = data_type {
294 Variable::new_data_value(
295 node_id,
296 browse_name,
297 display_name,
298 data_type.node_id,
299 None,
300 None,
301 value,
302 )
303 } else {
304 panic!("Data type cannot be inferred from the value, use another constructor such as new_data_value")
305 }
306 }
307
308 #[allow(clippy::too_many_arguments)]
314 pub fn new_full(
315 base: Base,
316 data_type: NodeId,
317 historizing: bool,
318 value_rank: i32,
319 value: DataValue,
320 access_level: u8,
321 user_access_level: u8,
322 array_dimensions: Option<Vec<u32>>,
323 minimum_sampling_interval: Option<f64>,
324 ) -> Self {
325 Self {
326 base,
327 data_type,
328 historizing,
329 value_rank,
330 value,
331 access_level,
332 user_access_level,
333 array_dimensions,
334 minimum_sampling_interval,
335 }
336 }
337
338 pub fn from_attributes(
340 node_id: &NodeId,
341 browse_name: impl Into<QualifiedName>,
342 attributes: VariableAttributes,
343 ) -> Result<Self, FromAttributesError> {
344 let mandatory_attributes = AttributesMask::DISPLAY_NAME
345 | AttributesMask::ACCESS_LEVEL
346 | AttributesMask::USER_ACCESS_LEVEL
347 | AttributesMask::DATA_TYPE
348 | AttributesMask::HISTORIZING
349 | AttributesMask::VALUE
350 | AttributesMask::VALUE_RANK;
351 let mask = AttributesMask::from_bits(attributes.specified_attributes)
352 .ok_or(FromAttributesError::InvalidMask)?;
353 if mask.contains(mandatory_attributes) {
354 let mut node = Self::new_data_value(
355 node_id,
356 browse_name,
357 attributes.display_name,
358 attributes.data_type,
359 None,
360 None,
361 attributes.value,
362 );
363 node.set_value_rank(attributes.value_rank);
364 node.set_historizing(attributes.historizing);
365 node.set_access_level(AccessLevel::from_bits_truncate(attributes.access_level));
366 node.set_user_access_level(AccessLevel::from_bits_truncate(
367 attributes.user_access_level,
368 ));
369
370 if mask.contains(AttributesMask::DESCRIPTION) {
371 node.set_description(attributes.description);
372 }
373 if mask.contains(AttributesMask::WRITE_MASK) {
374 node.set_write_mask(WriteMask::from_bits_truncate(attributes.write_mask));
375 }
376 if mask.contains(AttributesMask::USER_WRITE_MASK) {
377 node.set_user_write_mask(WriteMask::from_bits_truncate(attributes.user_write_mask));
378 }
379 if mask.contains(AttributesMask::ARRAY_DIMENSIONS) {
380 node.set_array_dimensions(attributes.array_dimensions.unwrap().as_slice());
381 }
382 if mask.contains(AttributesMask::MINIMUM_SAMPLING_INTERVAL) {
383 node.set_minimum_sampling_interval(attributes.minimum_sampling_interval);
384 }
385 Ok(node)
386 } else {
387 error!("Variable cannot be created from attributes - missing mandatory values");
388 Err(FromAttributesError::MissingMandatoryValues)
389 }
390 }
391
392 pub fn new_data_value<S, R, N, V>(
394 node_id: &NodeId,
395 browse_name: R,
396 display_name: S,
397 data_type: N,
398 value_rank: Option<i32>,
399 array_dimensions: Option<u32>,
400 value: V,
401 ) -> Variable
402 where
403 R: Into<QualifiedName>,
404 S: Into<LocalizedText>,
405 N: Into<NodeId>,
406 V: Into<Variant>,
407 {
408 let value = value.into();
409 let array_dimensions = if let Some(array_dimensions) = array_dimensions {
410 Some(vec![array_dimensions])
411 } else {
412 match value {
413 Variant::Array(ref array) => {
414 if let Some(ref array_dimensions) = array.dimensions {
415 Some(array_dimensions.to_vec())
418 } else {
419 Some(vec![array.values.len() as u32])
420 }
421 }
422 _ => None,
423 }
424 };
425
426 let value_rank = if let Some(value_rank) = value_rank {
427 value_rank
428 } else if let Some(ref array_dimensions) = array_dimensions {
429 array_dimensions.len() as i32
430 } else {
431 -1
432 };
433
434 let builder = VariableBuilder::new(node_id, browse_name, display_name)
435 .user_access_level(AccessLevel::CURRENT_READ)
436 .access_level(AccessLevel::CURRENT_READ)
437 .data_type(data_type)
438 .historizing(false)
439 .value_rank(value_rank)
440 .value(value);
441
442 let builder = if let Some(ref array_dimensions) = array_dimensions {
444 builder.array_dimensions(array_dimensions.as_slice())
445 } else {
446 builder
447 };
448 builder.build()
449 }
450
451 pub fn is_valid(&self) -> bool {
453 !self.data_type.is_null() && self.base.is_valid()
454 }
455
456 pub fn value(
458 &self,
459 timestamps_to_return: TimestampsToReturn,
460 index_range: &NumericRange,
461 _data_encoding: &DataEncoding,
462 _max_age: f64,
463 ) -> DataValue {
464 let data_value = &self.value;
465 let mut result = DataValue {
466 server_picoseconds: data_value.server_picoseconds,
467 server_timestamp: data_value.server_timestamp,
468 source_picoseconds: data_value.source_picoseconds,
469 source_timestamp: data_value.source_timestamp,
470 value: None,
471 status: None,
472 };
473
474 if let Some(ref value) = data_value.value {
476 match value.range_of(index_range) {
477 Ok(value) => {
478 result.value = Some(value);
479 result.status = data_value.status;
480 }
481 Err(err) => {
482 result.status = Some(err);
483 }
484 }
485 }
486
487 match timestamps_to_return {
488 TimestampsToReturn::Source => {
489 result.server_timestamp = None;
490 result.server_picoseconds = None;
491 }
492 TimestampsToReturn::Server => {
493 result.source_timestamp = None;
494 result.source_picoseconds = None;
495 }
496 TimestampsToReturn::Neither => {
497 result.server_timestamp = None;
498 result.source_timestamp = None;
499 result.server_picoseconds = None;
500 result.source_picoseconds = None;
501 }
502 _ => (),
503 }
504
505 result
506 }
508
509 pub fn set_value<V>(&mut self, index_range: &NumericRange, value: V) -> Result<(), StatusCode>
511 where
512 V: Into<Variant>,
513 {
514 let mut value = value.into();
515
516 match self.value_rank {
519 -3 | -2 | 1 => {
520 if self.data_type == DataTypeId::Byte {
521 if let Variant::ByteString(_) = value {
522 value = value
524 .to_byte_array()
525 .map_err(|_| StatusCode::BadUnexpectedError)?;
526 }
527 }
528 }
529 _ => { }
530 };
531
532 let now = DateTime::now();
533 if index_range.has_range() {
534 self.set_value_range(value, index_range, StatusCode::Good, &now, &now)
535 } else {
536 self.set_value_direct(value, StatusCode::Good, &now, &now)
537 }
538 }
540
541 pub fn set_value_range(
543 &mut self,
544 value: Variant,
545 index_range: &NumericRange,
546 status_code: StatusCode,
547 server_timestamp: &DateTime,
548 source_timestamp: &DateTime,
549 ) -> Result<(), StatusCode> {
550 if matches!(index_range, NumericRange::None) {
551 self.value.value = Some(value);
552 self.value.status = Some(status_code);
553 self.value.server_timestamp = Some(*server_timestamp);
554 self.value.source_timestamp = Some(*source_timestamp);
555 return Ok(());
556 }
557
558 match self.value.value {
559 Some(ref mut full_value) => {
560 full_value.set_range_of(index_range, &value)?;
562 self.value.status = Some(status_code);
563 self.value.server_timestamp = Some(*server_timestamp);
564 self.value.source_timestamp = Some(*source_timestamp);
565 Ok(())
566 }
567 None => Err(StatusCode::BadIndexRangeInvalid),
568 }
569 }
570
571 pub fn set_value_direct<V>(
573 &mut self,
574 value: V,
575 status_code: StatusCode,
576 server_timestamp: &DateTime,
577 source_timestamp: &DateTime,
578 ) -> Result<(), StatusCode>
579 where
580 V: Into<Variant>,
581 {
582 self.value.value = Some(value.into());
583 self.value.status = Some(status_code);
584 self.value.server_timestamp = Some(*server_timestamp);
585 self.value.source_timestamp = Some(*source_timestamp);
586 Ok(())
587 }
588
589 pub fn set_data_value(&mut self, value: DataValue) {
591 self.value = value;
592 }
593
594 pub fn minimum_sampling_interval(&self) -> Option<f64> {
596 self.minimum_sampling_interval
597 }
598
599 pub fn set_minimum_sampling_interval(&mut self, minimum_sampling_interval: f64) {
605 self.minimum_sampling_interval = Some(minimum_sampling_interval);
606 }
607
608 pub fn is_readable(&self) -> bool {
611 self.access_level().contains(AccessLevel::CURRENT_READ)
612 }
613
614 pub fn is_writable(&self) -> bool {
617 self.access_level().contains(AccessLevel::CURRENT_WRITE)
618 }
619
620 pub fn set_writable(&mut self, writable: bool) {
622 let mut access_level = self.access_level();
623 if writable {
624 access_level.insert(AccessLevel::CURRENT_WRITE);
625 } else {
626 access_level.remove(AccessLevel::CURRENT_WRITE);
627 }
628 self.set_access_level(access_level);
629 }
630
631 pub fn access_level(&self) -> AccessLevel {
633 AccessLevel::from_bits_truncate(self.access_level)
634 }
635
636 pub fn set_access_level(&mut self, access_level: AccessLevel) {
638 self.access_level = access_level.bits();
639 }
640
641 pub fn is_user_readable(&self) -> bool {
643 self.user_access_level().contains(AccessLevel::CURRENT_READ)
644 }
645
646 pub fn is_user_writable(&self) -> bool {
648 self.user_access_level()
649 .contains(AccessLevel::CURRENT_WRITE)
650 }
651
652 pub fn user_access_level(&self) -> AccessLevel {
654 AccessLevel::from_bits_truncate(self.user_access_level)
655 }
656
657 pub fn set_user_access_level(&mut self, user_access_level: AccessLevel) {
659 self.user_access_level = user_access_level.bits();
660 }
661
662 pub fn value_rank(&self) -> i32 {
664 self.value_rank
665 }
666
667 pub fn set_value_rank(&mut self, value_rank: i32) {
669 self.value_rank = value_rank;
670 }
671
672 pub fn historizing(&self) -> bool {
675 self.historizing
676 }
677
678 pub fn set_historizing(&mut self, historizing: bool) {
681 self.historizing = historizing;
682 }
683
684 pub fn array_dimensions(&self) -> Option<Vec<u32>> {
686 self.array_dimensions.clone()
687 }
688
689 pub fn set_array_dimensions(&mut self, array_dimensions: &[u32]) {
691 self.array_dimensions = Some(array_dimensions.to_vec());
692 }
693
694 pub fn data_type(&self) -> NodeId {
696 self.data_type.clone()
697 }
698
699 pub fn set_data_type(&mut self, data_type: impl Into<NodeId>) {
701 self.data_type = data_type.into();
702 }
703}