Skip to main content

opcua_nodes/
lib.rs

1//! The nodes crate contains core types for generated address spaces.
2//!
3//! This includes types for each node class, some common enums for references,
4//! core event types, and core types for node set import.
5
6use bitflags::bitflags;
7
8mod events;
9mod generic;
10mod import;
11mod references;
12mod type_tree;
13#[cfg(feature = "xml")]
14mod xml;
15#[cfg(feature = "xml")]
16pub use xml::NodeSet2Import;
17
18pub use base::Base;
19pub use data_type::{DataType, DataTypeBuilder};
20pub use events::*;
21pub use generic::new_node_from_attributes;
22pub use import::{ImportedItem, ImportedReference, NodeSetImport, NodeSetNamespaceMapper};
23pub use method::{Method, MethodBuilder};
24pub use node::{HasNodeId, Node, NodeBase, NodeType};
25pub use object::{Object, ObjectBuilder};
26pub use object_type::{ObjectType, ObjectTypeBuilder};
27pub use opcua_types::NamespaceMap;
28use opcua_types::NodeId;
29pub use reference_type::{ReferenceType, ReferenceTypeBuilder};
30pub use references::{Reference, ReferenceRef, References};
31pub use type_tree::{
32    DefaultTypeTree, TypeProperty, TypePropertyInverseRef, TypeTree, TypeTreeNode,
33};
34pub use variable::{Variable, VariableBuilder};
35pub use variable_type::{VariableType, VariableTypeBuilder};
36pub use view::{View, ViewBuilder};
37
38pub use opcua_macros::{Event, EventField};
39
40#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
41/// Direction of a reference in the address space.
42pub enum ReferenceDirection {
43    /// Reference from the source node to the target.
44    Forward,
45    /// Reference from the target node to the source.
46    Inverse,
47}
48
49#[derive(Debug)]
50/// Error returned when creating a node from attributes.
51pub enum FromAttributesError {
52    /// The provided attribute mask is invalid.
53    InvalidMask,
54    /// The provided attributes are missing mandatory values.
55    MissingMandatoryValues,
56}
57
58/// Something a list of nodes can be inserted into. Implemented for
59/// AddressSpace in the server crate.
60pub trait NodeInsertTarget {
61    /// Insert a node with a list of references into a target.
62    fn insert<'a>(
63        &mut self,
64        node: impl Into<NodeType>,
65        references: Option<&'a [(&'a NodeId, &NodeId, ReferenceDirection)]>,
66    ) -> bool;
67}
68
69// A macro for creating builders. Builders can be used for more conveniently creating objects,
70// variables etc.
71macro_rules! node_builder_impl {
72    ( $node_builder_ty:ident, $node_ty:ident ) => {
73        use opcua_types::{LocalizedText, NodeId, QualifiedName, ReferenceTypeId};
74        use tracing::trace;
75        use $crate::ReferenceDirection;
76        // use $crate::{address_space::AddressSpace, ReferenceDirection};
77
78        /// A builder for constructing a node of same name. This can be used as an easy way
79        /// to create a node and the references it has to another node in a simple fashion.
80        pub struct $node_builder_ty {
81            node: $node_ty,
82            references: Vec<(NodeId, NodeId, ReferenceDirection)>,
83        }
84
85        impl $node_builder_ty {
86            /// Creates a builder for a node. All nodes are required to su
87            pub fn new<T, S>(node_id: &NodeId, browse_name: T, display_name: S) -> Self
88            where
89                T: Into<QualifiedName>,
90                S: Into<LocalizedText>,
91            {
92                trace!("Creating a node using a builder, node id {}", node_id);
93                Self {
94                    node: $node_ty::default(),
95                    references: Vec::with_capacity(10),
96                }
97                .node_id(node_id.clone())
98                .browse_name(browse_name)
99                .display_name(display_name)
100            }
101
102            /// Get the node ID of the node being built.
103            pub fn get_node_id(&self) -> &NodeId {
104                self.node.node_id()
105            }
106
107            fn node_id(mut self, node_id: NodeId) -> Self {
108                let _ = self.node.base.set_node_id(node_id);
109                self
110            }
111
112            fn browse_name<V>(mut self, browse_name: V) -> Self
113            where
114                V: Into<QualifiedName>,
115            {
116                let _ = self.node.base.set_browse_name(browse_name);
117                self
118            }
119
120            fn display_name<V>(mut self, display_name: V) -> Self
121            where
122                V: Into<LocalizedText>,
123            {
124                self.node.set_display_name(display_name.into());
125                self
126            }
127
128            /// Tests that the builder is in a valid state to build or insert the node.
129            pub fn is_valid(&self) -> bool {
130                self.node.is_valid()
131            }
132
133            /// Sets the description of the node
134            pub fn description<V>(mut self, description: V) -> Self
135            where
136                V: Into<LocalizedText>,
137            {
138                self.node.set_description(description.into());
139                self
140            }
141
142            /// Adds a reference to the node
143            pub fn reference<T>(
144                mut self,
145                node_id: T,
146                reference_type_id: ReferenceTypeId,
147                reference_direction: ReferenceDirection,
148            ) -> Self
149            where
150                T: Into<NodeId>,
151            {
152                self.references.push((
153                    node_id.into(),
154                    reference_type_id.into(),
155                    reference_direction,
156                ));
157                self
158            }
159
160            /// Indicates this node organizes another node by its id.
161            pub fn organizes<T>(self, organizes_id: T) -> Self
162            where
163                T: Into<NodeId>,
164            {
165                self.reference(
166                    organizes_id,
167                    ReferenceTypeId::Organizes,
168                    ReferenceDirection::Forward,
169                )
170            }
171
172            /// Indicates this node is organised by another node by its id
173            pub fn organized_by<T>(self, organized_by_id: T) -> Self
174            where
175                T: Into<NodeId>,
176            {
177                self.reference(
178                    organized_by_id,
179                    ReferenceTypeId::Organizes,
180                    ReferenceDirection::Inverse,
181                )
182            }
183
184            /// Yields a built node. This function will panic if the node is invalid. Note that
185            /// calling this function discards any references for the node, so there is no purpose
186            /// in adding references if you intend to call this method.
187            pub fn build(self) -> $node_ty {
188                if self.is_valid() {
189                    self.node
190                } else {
191                    panic!(
192                        "The node is not valid, node id = {:?}",
193                        self.node.base.node_id()
194                    );
195                }
196            }
197
198            /// Inserts the node into the address space, including references. This function
199            /// will panic if the node is in an invalid state.
200            pub fn insert(self, address_space: &mut impl crate::NodeInsertTarget) -> bool {
201                if self.is_valid() {
202                    if !self.references.is_empty() {
203                        let references = self
204                            .references
205                            .iter()
206                            .map(|v| (&v.0, &v.1, v.2))
207                            .collect::<Vec<_>>();
208                        address_space.insert(self.node, Some(references.as_slice()))
209                    } else {
210                        address_space.insert(self.node, None)
211                    }
212                } else {
213                    panic!(
214                        "The node is not valid, node id = {:?}",
215                        self.node.base.node_id()
216                    );
217                }
218            }
219        }
220    };
221}
222
223macro_rules! node_builder_impl_generates_event {
224    ( $node_builder_ty:ident ) => {
225        impl $node_builder_ty {
226            /// Add a `GeneratesEvent` reference to the given event type.
227            pub fn generates_event<T>(self, event_type: T) -> Self
228            where
229                T: Into<NodeId>,
230            {
231                self.reference(
232                    event_type,
233                    ReferenceTypeId::GeneratesEvent,
234                    ReferenceDirection::Forward,
235                )
236            }
237        }
238    };
239}
240
241macro_rules! node_builder_impl_subtype {
242    ( $node_builder_ty:ident ) => {
243        impl $node_builder_ty {
244            /// Add an inverse `HasSubtype` reference to the given
245            /// type.
246            pub fn subtype_of<T>(self, type_id: T) -> Self
247            where
248                T: Into<NodeId>,
249            {
250                self.reference(
251                    type_id,
252                    ReferenceTypeId::HasSubtype,
253                    ReferenceDirection::Inverse,
254                )
255            }
256
257            /// Add a `HasSubtype` reference to the given type.
258            pub fn has_subtype<T>(self, subtype_id: T) -> Self
259            where
260                T: Into<NodeId>,
261            {
262                self.reference(
263                    subtype_id,
264                    ReferenceTypeId::HasSubtype,
265                    ReferenceDirection::Forward,
266                )
267            }
268        }
269    };
270}
271
272macro_rules! node_builder_impl_component_of {
273    ( $node_builder_ty:ident ) => {
274        impl $node_builder_ty {
275            /// Add an inverse `HasComponent` reference to the
276            /// given node.
277            pub fn component_of<T>(self, component_of_id: T) -> Self
278            where
279                T: Into<NodeId>,
280            {
281                self.reference(
282                    component_of_id,
283                    ReferenceTypeId::HasComponent,
284                    ReferenceDirection::Inverse,
285                )
286            }
287            /// Add a `HasComponent` reference to the
288            /// given node.
289            pub fn has_component<T>(self, has_component_id: T) -> Self
290            where
291                T: Into<NodeId>,
292            {
293                self.reference(
294                    has_component_id,
295                    ReferenceTypeId::HasComponent,
296                    ReferenceDirection::Forward,
297                )
298            }
299        }
300    };
301}
302
303macro_rules! node_builder_impl_property_of {
304    ( $node_builder_ty:ident ) => {
305        impl $node_builder_ty {
306            /// Add a `HasProperty` reference to the given node.
307            pub fn has_property<T>(self, has_component_id: T) -> Self
308            where
309                T: Into<NodeId>,
310            {
311                self.reference(
312                    has_component_id,
313                    ReferenceTypeId::HasProperty,
314                    ReferenceDirection::Forward,
315                )
316            }
317
318            /// Add an inverse `HasProperty` reference to the given node.
319            pub fn property_of<T>(self, component_of_id: T) -> Self
320            where
321                T: Into<NodeId>,
322            {
323                self.reference(
324                    component_of_id,
325                    ReferenceTypeId::HasProperty,
326                    ReferenceDirection::Inverse,
327                )
328            }
329        }
330    };
331}
332
333/// This is a sanity saving macro that implements the NodeBase trait for nodes. It assumes the
334/// node has a base: Base
335macro_rules! node_base_impl {
336    ( $node_struct:ident ) => {
337        use crate::NodeType;
338        use opcua_types::{NodeClass, WriteMask};
339
340        impl From<$node_struct> for NodeType {
341            fn from(value: $node_struct) -> Self {
342                Self::$node_struct(Box::new(value))
343            }
344        }
345
346        impl crate::NodeBase for $node_struct {
347            fn node_class(&self) -> NodeClass {
348                self.base.node_class()
349            }
350
351            fn node_id(&self) -> &NodeId {
352                self.base.node_id()
353            }
354
355            fn browse_name(&self) -> &QualifiedName {
356                self.base.browse_name()
357            }
358
359            fn display_name(&self) -> &LocalizedText {
360                self.base.display_name()
361            }
362
363            fn set_display_name(&mut self, display_name: LocalizedText) {
364                self.base.set_display_name(display_name);
365            }
366
367            fn description(&self) -> Option<&LocalizedText> {
368                self.base.description()
369            }
370
371            fn set_description(&mut self, description: LocalizedText) {
372                self.base.set_description(description);
373            }
374
375            fn write_mask(&self) -> Option<WriteMask> {
376                self.base.write_mask()
377            }
378
379            fn set_write_mask(&mut self, write_mask: WriteMask) {
380                self.base.set_write_mask(write_mask);
381            }
382
383            fn user_write_mask(&self) -> Option<WriteMask> {
384                self.base.user_write_mask()
385            }
386
387            fn set_user_write_mask(&mut self, user_write_mask: WriteMask) {
388                self.base.set_user_write_mask(user_write_mask)
389            }
390        }
391    };
392}
393
394mod base;
395mod data_type;
396// mod generated;
397mod method;
398mod node;
399mod object;
400mod object_type;
401mod reference_type;
402mod variable;
403mod variable_type;
404mod view;
405
406bitflags! {
407    #[derive(Debug, Clone, Copy, Default)]
408    /// Variable access level.
409    pub struct AccessLevel: u8 {
410        /// Read the current value of the node.
411        const CURRENT_READ = 1;
412        /// Write the current value of the node.
413        const CURRENT_WRITE = 2;
414        /// Read historical values of the node.
415        const HISTORY_READ = 4;
416        /// Write historical values of the node.
417        const HISTORY_WRITE = 8;
418        /// Allow changing properties that define semantics of the parent node.
419        const SEMANTIC_CHANGE = 16;
420        /// Write the status code of the current value.
421        const STATUS_WRITE = 32;
422        /// Write the timestamp of the current value.
423        const TIMESTAMP_WRITE = 64;
424    }
425}
426
427bitflags! {
428    #[derive(Debug, Clone, Copy, Default)]
429    /// Node event notifier.
430    pub struct EventNotifier: u8 {
431        /// Allow subscribing to events.
432        const SUBSCRIBE_TO_EVENTS = 1;
433        /// Allow reading historical events.
434        const HISTORY_READ = 4;
435        /// Allow writing historical events.
436        const HISTORY_WRITE = 8;
437    }
438}