Skip to main content

opcua_nodes/
object.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2024 Adam Lock
4
5//! Contains the implementation of `Object` and `ObjectBuilder`.
6
7use opcua_types::{
8    AttributeId, AttributesMask, DataEncoding, DataValue, NumericRange, ObjectAttributes,
9    ObjectTypeId, StatusCode, TimestampsToReturn, Variant,
10};
11use tracing::error;
12
13use crate::FromAttributesError;
14
15use super::{base::Base, node::Node, node::NodeBase, EventNotifier};
16
17node_builder_impl!(ObjectBuilder, Object);
18node_builder_impl_component_of!(ObjectBuilder);
19node_builder_impl_property_of!(ObjectBuilder);
20
21impl ObjectBuilder {
22    /// Get whether this is building an object with `FolderType` as the
23    /// type definition.
24    pub fn is_folder(self) -> Self {
25        self.has_type_definition(ObjectTypeId::FolderType)
26    }
27
28    /// Set the event notifier of the object.
29    pub fn event_notifier(mut self, event_notifier: EventNotifier) -> Self {
30        self.node.set_event_notifier(event_notifier);
31        self
32    }
33
34    /// Set the write mask of the object.
35    pub fn write_mask(mut self, write_mask: WriteMask) -> Self {
36        self.node.set_write_mask(write_mask);
37        self
38    }
39
40    /// Add a `HasTypeDefinition` reference to the given object type.
41    pub fn has_type_definition(self, type_id: impl Into<NodeId>) -> Self {
42        self.reference(
43            type_id,
44            ReferenceTypeId::HasTypeDefinition,
45            ReferenceDirection::Forward,
46        )
47    }
48
49    /// Add a `HasEventSource` reference to the given node.
50    pub fn has_event_source(self, source_id: impl Into<NodeId>) -> Self {
51        self.reference(
52            source_id,
53            ReferenceTypeId::HasEventSource,
54            ReferenceDirection::Forward,
55        )
56    }
57}
58
59/// An `Object` is a type of node within the `AddressSpace`.
60#[derive(Debug)]
61pub struct Object {
62    pub(super) base: Base,
63    pub(super) event_notifier: EventNotifier,
64}
65
66impl Default for Object {
67    fn default() -> Self {
68        Self {
69            base: Base::new(NodeClass::Object, &NodeId::null(), "", ""),
70            event_notifier: EventNotifier::empty(),
71        }
72    }
73}
74
75node_base_impl!(Object);
76
77impl Node for Object {
78    fn get_attribute_max_age(
79        &self,
80        timestamps_to_return: TimestampsToReturn,
81        attribute_id: AttributeId,
82        index_range: &NumericRange,
83        data_encoding: &DataEncoding,
84        max_age: f64,
85    ) -> Option<DataValue> {
86        match attribute_id {
87            AttributeId::EventNotifier => Some(self.event_notifier().bits().into()),
88            _ => self.base.get_attribute_max_age(
89                timestamps_to_return,
90                attribute_id,
91                index_range,
92                data_encoding,
93                max_age,
94            ),
95        }
96    }
97
98    fn set_attribute(
99        &mut self,
100        attribute_id: AttributeId,
101        value: Variant,
102    ) -> Result<(), StatusCode> {
103        match attribute_id {
104            AttributeId::EventNotifier => {
105                if let Variant::Byte(v) = value {
106                    self.set_event_notifier(EventNotifier::from_bits_truncate(v));
107                    Ok(())
108                } else {
109                    Err(StatusCode::BadTypeMismatch)
110                }
111            }
112            _ => self.base.set_attribute(attribute_id, value),
113        }
114    }
115}
116
117impl Object {
118    /// Create a new object.
119    pub fn new(
120        node_id: &NodeId,
121        browse_name: impl Into<QualifiedName>,
122        display_name: impl Into<LocalizedText>,
123        event_notifier: EventNotifier,
124    ) -> Object {
125        Object {
126            base: Base::new(NodeClass::Object, node_id, browse_name, display_name),
127            event_notifier,
128        }
129    }
130
131    /// Create a new object with all attributes, may change if
132    /// new attributes are added to the OPC-UA standard.
133    pub fn new_full(base: Base, event_notifier: EventNotifier) -> Self {
134        Self {
135            base,
136            event_notifier,
137        }
138    }
139
140    /// Create a new object from [ObjectAttributes].
141    pub fn from_attributes(
142        node_id: &NodeId,
143        browse_name: impl Into<QualifiedName>,
144        attributes: ObjectAttributes,
145    ) -> Result<Self, FromAttributesError> {
146        let mandatory_attributes = AttributesMask::DISPLAY_NAME | AttributesMask::EVENT_NOTIFIER;
147
148        let mask = AttributesMask::from_bits(attributes.specified_attributes)
149            .ok_or(FromAttributesError::InvalidMask)?;
150        if mask.contains(mandatory_attributes) {
151            let event_notifier = EventNotifier::from_bits_truncate(attributes.event_notifier);
152            let mut node = Self::new(
153                node_id,
154                browse_name,
155                attributes.display_name,
156                event_notifier,
157            );
158            if mask.contains(AttributesMask::DESCRIPTION) {
159                node.set_description(attributes.description);
160            }
161            if mask.contains(AttributesMask::WRITE_MASK) {
162                node.set_write_mask(WriteMask::from_bits_truncate(attributes.write_mask));
163            }
164            if mask.contains(AttributesMask::USER_WRITE_MASK) {
165                node.set_user_write_mask(WriteMask::from_bits_truncate(attributes.user_write_mask));
166            }
167            Ok(node)
168        } else {
169            error!("Object cannot be created from attributes - missing mandatory values");
170            Err(FromAttributesError::MissingMandatoryValues)
171        }
172    }
173
174    /// Get whether this object is valid.
175    pub fn is_valid(&self) -> bool {
176        self.base.is_valid()
177    }
178
179    /// Get the event notifier status of this object.
180    pub fn event_notifier(&self) -> EventNotifier {
181        self.event_notifier
182    }
183
184    /// Set the event notifier status of this object.
185    pub fn set_event_notifier(&mut self, event_notifier: EventNotifier) {
186        self.event_notifier = event_notifier;
187    }
188}