1use opcua_types::{
6 status_code::StatusCode, AttributeId, DataEncoding, DataValue, LocalizedText, NodeClass,
7 NodeId, NumericRange, QualifiedName, TimestampsToReturn, Variant, WriteMask,
8};
9
10use super::node::{Node, NodeBase};
11
12#[derive(Debug)]
14pub struct Base {
15 pub(super) node_id: NodeId,
17 pub(super) node_class: NodeClass,
19 pub(super) browse_name: QualifiedName,
21 pub(super) display_name: LocalizedText,
23 pub(super) description: Option<LocalizedText>,
25 pub(super) write_mask: Option<u32>,
27 pub(super) user_write_mask: Option<u32>,
29}
30
31impl NodeBase for Base {
32 fn node_class(&self) -> NodeClass {
33 self.node_class
34 }
35
36 fn node_id(&self) -> &NodeId {
37 &self.node_id
38 }
39
40 fn browse_name(&self) -> &QualifiedName {
41 &self.browse_name
42 }
43
44 fn display_name(&self) -> &LocalizedText {
45 &self.display_name
46 }
47
48 fn set_display_name(&mut self, display_name: LocalizedText) {
49 self.display_name = display_name;
50 }
51
52 fn description(&self) -> Option<&LocalizedText> {
53 self.description.as_ref()
54 }
55
56 fn set_description(&mut self, description: LocalizedText) {
57 self.description = Some(description)
58 }
59
60 fn write_mask(&self) -> Option<WriteMask> {
61 self.write_mask.map(WriteMask::from_bits_truncate)
62 }
63
64 fn set_write_mask(&mut self, write_mask: WriteMask) {
65 self.write_mask = Some(write_mask.bits());
66 }
67
68 fn user_write_mask(&self) -> Option<WriteMask> {
69 self.user_write_mask.map(WriteMask::from_bits_truncate)
70 }
71
72 fn set_user_write_mask(&mut self, user_write_mask: WriteMask) {
73 self.user_write_mask = Some(user_write_mask.bits());
74 }
75}
76
77impl Node for Base {
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::NodeClass => Some((self.node_class as i32).into()),
88 AttributeId::NodeId => Some(self.node_id().clone().into()),
89 AttributeId::BrowseName => Some(self.browse_name().clone().into()),
90 AttributeId::DisplayName => Some(self.display_name().clone().into()),
91 AttributeId::Description => self
92 .description()
93 .cloned()
94 .map(|description| description.into()),
95 AttributeId::WriteMask => self.write_mask.map(|v| v.into()),
96 AttributeId::UserWriteMask => self.user_write_mask.map(|v| v.into()),
97 _ => None,
98 }
99 }
100
101 fn set_attribute(
104 &mut self,
105 attribute_id: AttributeId,
106 value: Variant,
107 ) -> Result<(), StatusCode> {
108 match attribute_id {
109 AttributeId::NodeClass => {
110 if let Variant::Int32(v) = value {
111 self.node_class = match v {
112 1 => NodeClass::Object,
113 2 => NodeClass::Variable,
114 4 => NodeClass::Method,
115 8 => NodeClass::ObjectType,
116 16 => NodeClass::VariableType,
117 32 => NodeClass::ReferenceType,
118 64 => NodeClass::DataType,
119 128 => NodeClass::View,
120 _ => {
121 return Ok(());
122 }
123 };
124 Ok(())
125 } else {
126 Err(StatusCode::BadTypeMismatch)
127 }
128 }
129 AttributeId::NodeId => {
130 if let Variant::NodeId(v) = value {
131 self.node_id = *v;
132 Ok(())
133 } else {
134 Err(StatusCode::BadTypeMismatch)
135 }
136 }
137 AttributeId::BrowseName => {
138 if let Variant::QualifiedName(v) = value {
139 self.browse_name = *v;
140 Ok(())
141 } else {
142 Err(StatusCode::BadTypeMismatch)
143 }
144 }
145 AttributeId::DisplayName => {
146 if let Variant::LocalizedText(v) = value {
147 self.display_name = *v;
148 Ok(())
149 } else {
150 Err(StatusCode::BadTypeMismatch)
151 }
152 }
153 AttributeId::Description => {
154 if let Variant::LocalizedText(v) = value {
155 self.description = Some(*v);
156 Ok(())
157 } else {
158 Err(StatusCode::BadTypeMismatch)
159 }
160 }
161 AttributeId::WriteMask => {
162 if let Variant::UInt32(v) = value {
163 self.write_mask = Some(v);
164 Ok(())
165 } else {
166 Err(StatusCode::BadTypeMismatch)
167 }
168 }
169 AttributeId::UserWriteMask => {
170 if let Variant::UInt32(v) = value {
171 self.user_write_mask = Some(v);
172 Ok(())
173 } else {
174 Err(StatusCode::BadTypeMismatch)
175 }
176 }
177 _ => Err(StatusCode::BadAttributeIdInvalid),
178 }
179 }
180}
181
182impl Base {
183 pub fn new(
185 node_class: NodeClass,
186 node_id: &NodeId,
187 browse_name: impl Into<QualifiedName>,
188 display_name: impl Into<LocalizedText>,
189 ) -> Base {
190 Base {
191 node_id: node_id.clone(),
192 node_class,
193 browse_name: browse_name.into(),
194 display_name: display_name.into(),
195 description: None,
196 write_mask: None,
197 user_write_mask: None,
198 }
199 }
200
201 pub fn new_full(
204 node_id: NodeId,
205 node_class: NodeClass,
206 browse_name: QualifiedName,
207 display_name: LocalizedText,
208 description: Option<LocalizedText>,
209 write_mask: Option<u32>,
210 user_write_mask: Option<u32>,
211 ) -> Self {
212 Self {
213 node_id,
214 node_class,
215 browse_name,
216 display_name,
217 description,
218 write_mask,
219 user_write_mask,
220 }
221 }
222
223 pub fn is_valid(&self) -> bool {
225 let invalid = self.node_id().is_null() || self.browse_name.is_null();
226 !invalid
227 }
228
229 pub fn set_node_id(&mut self, node_id: NodeId) {
231 self.node_id = node_id;
232 }
233
234 pub fn set_browse_name(&mut self, browse_name: impl Into<QualifiedName>) {
236 self.browse_name = browse_name.into();
237 }
238}