Skip to main content

opcua/server/address_space/
mod.rs

1// OPCUA for Rust
2// SPDX-License-Identifier: MPL-2.0
3// Copyright (C) 2017-2022 Adam Lock
4
5//! Provides functionality to create an address space, find nodes, add nodes, change attributes
6//! and values on nodes.
7
8use std::{result::Result, sync::Arc};
9
10use crate::sync::*;
11use crate::types::status_code::StatusCode;
12use crate::types::{
13    AttributeId, DataValue, NodeId, NumericRange, QualifiedName, TimestampsToReturn,
14};
15
16use super::callbacks::{AttributeGetter, AttributeSetter};
17
18pub use self::address_space::AddressSpace;
19
20/// An implementation of attribute getter that can be easily constructed from a mutable function
21pub struct AttrFnGetter<F>
22where
23    F: FnMut(
24            &NodeId,
25            TimestampsToReturn,
26            AttributeId,
27            NumericRange,
28            &QualifiedName,
29            f64,
30        ) -> Result<Option<DataValue>, StatusCode>
31        + Send,
32{
33    getter: F,
34}
35
36impl<F> AttributeGetter for AttrFnGetter<F>
37where
38    F: FnMut(
39            &NodeId,
40            TimestampsToReturn,
41            AttributeId,
42            NumericRange,
43            &QualifiedName,
44            f64,
45        ) -> Result<Option<DataValue>, StatusCode>
46        + Send,
47{
48    fn get(
49        &mut self,
50        node_id: &NodeId,
51        timestamps_to_return: TimestampsToReturn,
52        attribute_id: AttributeId,
53        index_range: NumericRange,
54        data_encoding: &QualifiedName,
55        max_age: f64,
56    ) -> Result<Option<DataValue>, StatusCode> {
57        (self.getter)(
58            node_id,
59            timestamps_to_return,
60            attribute_id,
61            index_range,
62            data_encoding,
63            max_age,
64        )
65    }
66}
67
68impl<F> AttrFnGetter<F>
69where
70    F: FnMut(
71            &NodeId,
72            TimestampsToReturn,
73            AttributeId,
74            NumericRange,
75            &QualifiedName,
76            f64,
77        ) -> Result<Option<DataValue>, StatusCode>
78        + Send,
79{
80    pub fn new(getter: F) -> AttrFnGetter<F> {
81        AttrFnGetter { getter }
82    }
83
84    pub fn new_boxed(getter: F) -> Arc<Mutex<AttrFnGetter<F>>> {
85        Arc::new(Mutex::new(Self::new(getter)))
86    }
87}
88
89/// An implementation of attribute setter that can be easily constructed using a mutable function
90pub struct AttrFnSetter<F>
91where
92    F: FnMut(&NodeId, AttributeId, NumericRange, DataValue) -> Result<(), StatusCode> + Send,
93{
94    setter: F,
95}
96
97impl<F> AttributeSetter for AttrFnSetter<F>
98where
99    F: FnMut(&NodeId, AttributeId, NumericRange, DataValue) -> Result<(), StatusCode> + Send,
100{
101    fn set(
102        &mut self,
103        node_id: &NodeId,
104        attribute_id: AttributeId,
105        index_range: NumericRange,
106        data_value: DataValue,
107    ) -> Result<(), StatusCode> {
108        (self.setter)(node_id, attribute_id, index_range, data_value)
109    }
110}
111
112impl<F> AttrFnSetter<F>
113where
114    F: FnMut(&NodeId, AttributeId, NumericRange, DataValue) -> Result<(), StatusCode> + Send,
115{
116    pub fn new(setter: F) -> AttrFnSetter<F> {
117        AttrFnSetter { setter }
118    }
119
120    pub fn new_boxed(setter: F) -> Arc<Mutex<AttrFnSetter<F>>> {
121        Arc::new(Mutex::new(Self::new(setter)))
122    }
123}
124
125// A macro for creating builders. Builders can be used for more conveniently creating objects,
126// variables etc.
127macro_rules! node_builder_impl {
128    ( $node_builder_ty:ident, $node_ty:ident ) => {
129        use $crate::server::address_space::{
130            address_space::AddressSpace, references::ReferenceDirection,
131        };
132
133        /// A builder for constructing a node of same name. This can be used as an easy way
134        /// to create a node and the references it has to another node in a simple fashion.
135        pub struct $node_builder_ty {
136            node: $node_ty,
137            references: Vec<(NodeId, NodeId, ReferenceDirection)>,
138        }
139
140        impl $node_builder_ty {
141            /// Creates a builder for a node. All nodes are required to su
142            pub fn new<T, S>(node_id: &NodeId, browse_name: T, display_name: S) -> Self
143            where
144                T: Into<QualifiedName>,
145                S: Into<LocalizedText>,
146            {
147                trace!("Creating a node using a builder, node id {}", node_id);
148                Self {
149                    node: $node_ty::default(),
150                    references: Vec::with_capacity(10),
151                }
152                .node_id(node_id.clone())
153                .browse_name(browse_name)
154                .display_name(display_name)
155            }
156
157            pub fn get_node_id(&self) -> NodeId {
158                self.node.node_id()
159            }
160
161            fn node_id(mut self, node_id: NodeId) -> Self {
162                let _ = self.node.base.set_node_id(node_id);
163                self
164            }
165
166            fn browse_name<V>(mut self, browse_name: V) -> Self
167            where
168                V: Into<QualifiedName>,
169            {
170                let _ = self.node.base.set_browse_name(browse_name);
171                self
172            }
173
174            fn display_name<V>(mut self, display_name: V) -> Self
175            where
176                V: Into<LocalizedText>,
177            {
178                self.node.set_display_name(display_name.into());
179                self
180            }
181
182            /// Tests that the builder is in a valid state to build or insert the node.
183            pub fn is_valid(&self) -> bool {
184                self.node.is_valid()
185            }
186
187            /// Sets the description of the node
188            pub fn description<V>(mut self, description: V) -> Self
189            where
190                V: Into<LocalizedText>,
191            {
192                self.node.set_description(description.into());
193                self
194            }
195
196            /// Adds a reference to the node
197            pub fn reference<T>(
198                mut self,
199                node_id: T,
200                reference_type_id: ReferenceTypeId,
201                reference_direction: ReferenceDirection,
202            ) -> Self
203            where
204                T: Into<NodeId>,
205            {
206                self.references.push((
207                    node_id.into(),
208                    reference_type_id.into(),
209                    reference_direction,
210                ));
211                self
212            }
213
214            /// Indicates this node organizes another node by its id.
215            pub fn organizes<T>(self, organizes_id: T) -> Self
216            where
217                T: Into<NodeId>,
218            {
219                self.reference(
220                    organizes_id,
221                    ReferenceTypeId::Organizes,
222                    ReferenceDirection::Forward,
223                )
224            }
225
226            /// Indicates this node is organised by another node by its id
227            pub fn organized_by<T>(self, organized_by_id: T) -> Self
228            where
229                T: Into<NodeId>,
230            {
231                self.reference(
232                    organized_by_id,
233                    ReferenceTypeId::Organizes,
234                    ReferenceDirection::Inverse,
235                )
236            }
237
238            /// Yields a built node. This function will panic if the node is invalid. Note that
239            /// calling this function discards any references for the node, so there is no purpose
240            /// in adding references if you intend to call this method.
241            pub fn build(self) -> $node_ty {
242                if self.is_valid() {
243                    self.node
244                } else {
245                    panic!(
246                        "The node is not valid, node id = {:?}",
247                        self.node.base.node_id()
248                    );
249                }
250            }
251
252            /// Inserts the node into the address space, including references. This function
253            /// will panic if the node is in an invalid state.
254            pub fn insert(self, address_space: &mut AddressSpace) -> bool {
255                if self.is_valid() {
256                    if !self.references.is_empty() {
257                        let references = self
258                            .references
259                            .iter()
260                            .map(|v| (&v.0, &v.1, v.2))
261                            .collect::<Vec<_>>();
262                        address_space.insert(self.node, Some(references.as_slice()))
263                    } else {
264                        address_space.insert::<$node_ty, ReferenceTypeId>(self.node, None)
265                    }
266                } else {
267                    panic!(
268                        "The node is not valid, node id = {:?}",
269                        self.node.base.node_id()
270                    );
271                }
272            }
273        }
274    };
275}
276
277macro_rules! node_builder_impl_generates_event {
278    ( $node_builder_ty:ident ) => {
279        impl $node_builder_ty {
280            pub fn generates_event<T>(self, event_type: T) -> Self
281            where
282                T: Into<NodeId>,
283            {
284                self.reference(
285                    event_type,
286                    ReferenceTypeId::GeneratesEvent,
287                    ReferenceDirection::Forward,
288                )
289            }
290        }
291    };
292}
293
294macro_rules! node_builder_impl_subtype {
295    ( $node_builder_ty:ident ) => {
296        impl $node_builder_ty {
297            pub fn subtype_of<T>(self, type_id: T) -> Self
298            where
299                T: Into<NodeId>,
300            {
301                self.reference(
302                    type_id,
303                    ReferenceTypeId::HasSubtype,
304                    ReferenceDirection::Inverse,
305                )
306            }
307
308            pub fn has_subtype<T>(self, subtype_id: T) -> Self
309            where
310                T: Into<NodeId>,
311            {
312                self.reference(
313                    subtype_id,
314                    ReferenceTypeId::HasSubtype,
315                    ReferenceDirection::Forward,
316                )
317            }
318        }
319    };
320}
321
322macro_rules! node_builder_impl_component_of {
323    ( $node_builder_ty:ident ) => {
324        impl $node_builder_ty {
325            pub fn component_of<T>(self, component_of_id: T) -> Self
326            where
327                T: Into<NodeId>,
328            {
329                self.reference(
330                    component_of_id,
331                    ReferenceTypeId::HasComponent,
332                    ReferenceDirection::Inverse,
333                )
334            }
335
336            pub fn has_component<T>(self, has_component_id: T) -> Self
337            where
338                T: Into<NodeId>,
339            {
340                self.reference(
341                    has_component_id,
342                    ReferenceTypeId::HasComponent,
343                    ReferenceDirection::Forward,
344                )
345            }
346        }
347    };
348}
349
350macro_rules! node_builder_impl_property_of {
351    ( $node_builder_ty:ident ) => {
352        impl $node_builder_ty {
353            pub fn has_property<T>(self, has_component_id: T) -> Self
354            where
355                T: Into<NodeId>,
356            {
357                self.reference(
358                    has_component_id,
359                    ReferenceTypeId::HasProperty,
360                    ReferenceDirection::Forward,
361                )
362            }
363
364            pub fn property_of<T>(self, component_of_id: T) -> Self
365            where
366                T: Into<NodeId>,
367            {
368                self.reference(
369                    component_of_id,
370                    ReferenceTypeId::HasProperty,
371                    ReferenceDirection::Inverse,
372                )
373            }
374        }
375    };
376}
377
378/// This is a sanity saving macro that implements the NodeBase trait for nodes. It assumes the
379/// node has a base: Base
380macro_rules! node_base_impl {
381    ( $node_struct:ident ) => {
382        use crate::{
383            server::address_space::node::NodeType,
384            types::{status_code::StatusCode, *},
385        };
386
387        impl Into<NodeType> for $node_struct {
388            fn into(self) -> NodeType {
389                NodeType::$node_struct(Box::new(self))
390            }
391        }
392
393        impl NodeBase for $node_struct {
394            fn node_class(&self) -> NodeClass {
395                self.base.node_class()
396            }
397
398            fn node_id(&self) -> NodeId {
399                self.base.node_id()
400            }
401
402            fn browse_name(&self) -> QualifiedName {
403                self.base.browse_name()
404            }
405
406            fn display_name(&self) -> LocalizedText {
407                self.base.display_name()
408            }
409
410            fn set_display_name(&mut self, display_name: LocalizedText) {
411                self.base.set_display_name(display_name);
412            }
413
414            fn description(&self) -> Option<LocalizedText> {
415                self.base.description()
416            }
417
418            fn set_description(&mut self, description: LocalizedText) {
419                self.base.set_description(description);
420            }
421
422            fn write_mask(&self) -> Option<WriteMask> {
423                self.base.write_mask()
424            }
425
426            fn set_write_mask(&mut self, write_mask: WriteMask) {
427                self.base.set_write_mask(write_mask);
428            }
429
430            fn user_write_mask(&self) -> Option<WriteMask> {
431                self.base.user_write_mask()
432            }
433
434            fn set_user_write_mask(&mut self, user_write_mask: WriteMask) {
435                self.base.set_user_write_mask(user_write_mask)
436            }
437        }
438    };
439}
440
441pub mod address_space;
442pub mod base;
443pub mod data_type;
444pub mod method;
445pub mod node;
446pub mod object;
447pub mod object_type;
448pub mod reference_type;
449pub mod references;
450pub mod relative_path;
451pub mod variable;
452pub mod variable_type;
453pub mod view;
454
455#[rustfmt::skip]
456#[cfg(feature = "generated-address-space")]
457mod generated;
458#[cfg(feature = "generated-address-space")]
459mod method_impls;
460
461bitflags! {
462    pub struct AccessLevel: u8 {
463        const CURRENT_READ = 1;
464        const CURRENT_WRITE = 2;
465        const HISTORY_READ = 4;
466        const HISTORY_WRITE = 8;
467        // These can be uncommented if they become used
468        // const SEMANTIC_CHANGE = 16;
469        // const STATUS_WRITE = 32;
470        // const TIMESTAMP_WRITE = 64;
471    }
472}
473
474bitflags! {
475    pub struct UserAccessLevel: u8 {
476        const CURRENT_READ = 1;
477        const CURRENT_WRITE = 2;
478        const HISTORY_READ = 4;
479        const HISTORY_WRITE = 8;
480        // These can be uncommented if they become used
481        // const STATUS_WRITE = 32;
482        // const TIMESTAMP_WRITE = 64;
483    }
484}
485
486bitflags! {
487    pub struct EventNotifier: u8 {
488        const SUBSCRIBE_TO_EVENTS = 1;
489        const HISTORY_READ = 4;
490        const HISTORY_WRITE = 8;
491    }
492}
493
494pub mod types {
495    pub use super::address_space::AddressSpace;
496    pub use super::data_type::{DataType, DataTypeBuilder};
497    pub use super::method::{Method, MethodBuilder};
498    pub use super::node::{NodeBase, NodeType};
499    pub use super::object::{Object, ObjectBuilder};
500    pub use super::object_type::{ObjectType, ObjectTypeBuilder};
501    pub use super::reference_type::{ReferenceType, ReferenceTypeBuilder};
502    pub use super::references::ReferenceDirection;
503    pub use super::variable::{Variable, VariableBuilder};
504    pub use super::variable_type::{VariableType, VariableTypeBuilder};
505    pub use super::view::{View, ViewBuilder};
506    pub use super::{AttrFnGetter, AttrFnSetter};
507}