Skip to main content

opcua/server/address_space/
object.rs

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