1use std::{
2 borrow::Borrow,
3 collections::{HashMap, HashSet},
4};
5
6use crate::NamespaceMap;
7use opcua_types::{
8 DataTypeId, NodeClass, NodeId, ObjectTypeId, QualifiedName, ReferenceTypeId, VariableTypeId,
9};
10
11#[derive(PartialEq, Eq, Hash, Clone)]
12struct TypePropertyKey {
13 path: Vec<QualifiedName>,
14}
15impl Borrow<[QualifiedName]> for TypePropertyKey {
18 fn borrow(&self) -> &[QualifiedName] {
19 &self.path
20 }
21}
22
23#[derive(Clone, Debug)]
24pub struct TypeProperty {
26 pub node_id: NodeId,
28 pub node_class: NodeClass,
30}
31
32#[derive(Clone, Debug)]
33pub struct TypePropertyInverseRef {
35 pub type_id: NodeId,
37 pub path: Vec<QualifiedName>,
39}
40
41#[derive(Default, Clone)]
48pub struct DefaultTypeTree {
49 nodes: HashMap<NodeId, NodeClass>,
50 subtypes_by_source: HashMap<NodeId, HashSet<NodeId>>,
51 subtypes_by_target: HashMap<NodeId, NodeId>,
52 property_to_type: HashMap<NodeId, TypePropertyInverseRef>,
53 type_properties: HashMap<NodeId, HashMap<TypePropertyKey, TypeProperty>>,
54 namespaces: NamespaceMap,
55}
56
57#[derive(Clone, Debug)]
58pub enum TypeTreeNode<'a> {
60 Type(NodeClass),
62 Property(&'a TypePropertyInverseRef),
64}
65
66pub trait TypeTree {
70 fn is_subtype_of(&self, child: &NodeId, ancestor: &NodeId) -> bool;
73
74 fn get_node<'a>(&'a self, node: &NodeId) -> Option<TypeTreeNode<'a>>;
76
77 fn get(&self, node: &NodeId) -> Option<NodeClass>;
79
80 fn find_type_prop_by_browse_path(
82 &self,
83 type_id: &NodeId,
84 path: &[QualifiedName],
85 ) -> Option<&TypeProperty>;
86
87 fn get_supertype<'a>(&'a self, node: &NodeId) -> Option<&'a NodeId>;
89
90 fn namespaces(&self) -> &NamespaceMap;
92}
93
94impl TypeTree for DefaultTypeTree {
95 fn is_subtype_of(&self, child: &NodeId, ancestor: &NodeId) -> bool {
98 let mut node = child;
99 loop {
100 if node == ancestor {
101 break true;
102 }
103
104 let Some(class) = self.nodes.get(node) else {
105 break false;
106 };
107
108 if !matches!(
109 class,
110 NodeClass::DataType
111 | NodeClass::ObjectType
112 | NodeClass::ReferenceType
113 | NodeClass::VariableType
114 ) {
115 break false;
116 }
117
118 match self.subtypes_by_target.get(node) {
119 Some(n) => node = n,
120 None => break false,
121 }
122 }
123 }
124
125 fn get_node<'a>(&'a self, node: &NodeId) -> Option<TypeTreeNode<'a>> {
127 if let Some(n) = self.nodes.get(node) {
128 return Some(TypeTreeNode::Type(*n));
129 }
130 if let Some(p) = self.property_to_type.get(node) {
131 return Some(TypeTreeNode::Property(p));
132 }
133 None
134 }
135
136 fn get(&self, node: &NodeId) -> Option<NodeClass> {
138 self.nodes.get(node).cloned()
139 }
140
141 fn find_type_prop_by_browse_path(
143 &self,
144 type_id: &NodeId,
145 path: &[QualifiedName],
146 ) -> Option<&TypeProperty> {
147 self.type_properties.get(type_id).and_then(|p| p.get(path))
148 }
149
150 fn get_supertype<'a>(&'a self, node: &NodeId) -> Option<&'a NodeId> {
151 self.subtypes_by_target.get(node)
152 }
153
154 fn namespaces(&self) -> &NamespaceMap {
155 &self.namespaces
156 }
157}
158
159impl DefaultTypeTree {
160 pub fn new() -> Self {
162 let mut type_tree = Self {
163 nodes: HashMap::new(),
164 subtypes_by_source: HashMap::new(),
165 subtypes_by_target: HashMap::new(),
166 type_properties: HashMap::new(),
167 property_to_type: HashMap::new(),
168 namespaces: NamespaceMap::new(),
169 };
170 type_tree
171 .namespaces
172 .add_namespace("http://opcfoundation.org/UA/");
173 type_tree
174 .nodes
175 .insert(ObjectTypeId::BaseObjectType.into(), NodeClass::ObjectType);
176 type_tree
177 .nodes
178 .insert(ReferenceTypeId::References.into(), NodeClass::ReferenceType);
179 type_tree.nodes.insert(
180 VariableTypeId::BaseVariableType.into(),
181 NodeClass::VariableType,
182 );
183 type_tree
184 .nodes
185 .insert(DataTypeId::BaseDataType.into(), NodeClass::DataType);
186 type_tree
187 }
188
189 pub fn add_type_node(&mut self, id: &NodeId, parent: &NodeId, node_class: NodeClass) {
191 self.nodes.insert(id.clone(), node_class);
192 self.subtypes_by_source
193 .entry(parent.clone())
194 .or_default()
195 .insert(id.clone());
196 self.subtypes_by_target.insert(id.clone(), parent.clone());
197 }
198
199 pub fn add_type_property(
201 &mut self,
202 id: &NodeId,
203 typ: &NodeId,
204 path: &[&QualifiedName],
205 node_class: NodeClass,
206 ) {
207 let props = match self.type_properties.get_mut(typ) {
208 Some(x) => x,
209 None => self.type_properties.entry(typ.clone()).or_default(),
210 };
211
212 let path_owned: Vec<_> = path.iter().map(|n| (*n).to_owned()).collect();
213
214 props.insert(
215 TypePropertyKey {
216 path: path_owned.clone(),
217 },
218 TypeProperty {
219 node_class,
220 node_id: id.clone(),
221 },
222 );
223
224 self.property_to_type.insert(
225 id.clone(),
226 TypePropertyInverseRef {
227 type_id: typ.clone(),
228 path: path_owned,
229 },
230 );
231 }
232
233 pub fn remove(&mut self, node_id: &NodeId) -> bool {
235 if self.nodes.remove(node_id).is_some() {
236 let props = self.type_properties.remove(node_id);
237 if let Some(props) = props {
238 for prop in props.values() {
239 self.property_to_type.remove(&prop.node_id);
240 }
241 }
242 if let Some(parent) = self.subtypes_by_target.remove(node_id) {
243 if let Some(types) = self.subtypes_by_source.get_mut(&parent) {
244 types.remove(node_id);
245 }
246 }
247 return true;
248 }
249 if let Some(prop) = self.property_to_type.remove(node_id) {
250 let props = self.type_properties.get_mut(&prop.type_id);
251 if let Some(props) = props {
252 props.remove(&prop.path as &[QualifiedName]);
253 }
254 return true;
255 }
256 false
257 }
258
259 pub fn namespaces_mut(&mut self) -> &mut NamespaceMap {
261 &mut self.namespaces
262 }
263
264 pub fn namespaces(&self) -> &NamespaceMap {
266 &self.namespaces
267 }
268
269 pub fn get_all_children<'a>(&'a self, root: &'a NodeId) -> Vec<&'a NodeId> {
271 let mut res = Vec::new();
272 let mut roots = vec![root];
273 loop {
274 let Some(root) = roots.pop() else {
275 break;
276 };
277 res.push(root);
278 let Some(children) = self.subtypes_by_source.get(root) else {
279 continue;
280 };
281 for child in children.iter() {
282 roots.push(child);
283 }
284 }
285
286 res
287 }
288}