1use std::hash::Hasher;
2
3use hashbrown::{Equivalent, HashMap, HashSet};
4use opcua_types::{
5 node_id::{IdentifierRef, IntoNodeIdRef, NodeIdRef},
6 BrowseDirection, Identifier, NodeId,
7};
8
9use crate::{ImportedReference, ReferenceDirection, TypeTree};
10
11#[derive(PartialEq, Eq, Clone, Debug, Hash)]
12pub struct Reference {
14 pub reference_type: NodeId,
16 pub target_node: NodeId,
18}
19
20#[derive(PartialEq, Eq, Clone, Debug)]
22struct ReferenceKey<R: IdentifierRef, R2: IdentifierRef> {
23 pub reference_type: NodeIdRef<R2>,
24 pub target_node: NodeIdRef<R>,
25}
26
27impl<R, R2> std::hash::Hash for ReferenceKey<R, R2>
28where
29 R: IdentifierRef,
30 R2: IdentifierRef,
31{
32 fn hash<H: Hasher>(&self, state: &mut H) {
33 self.reference_type.hash(state);
34 self.target_node.hash(state);
35 }
36}
37
38impl<R, R2> Equivalent<Reference> for ReferenceKey<R, R2>
39where
40 R: IdentifierRef,
41 R2: IdentifierRef,
42{
43 fn equivalent(&self, key: &Reference) -> bool {
44 self.reference_type.equivalent(&key.reference_type)
45 && self.target_node.equivalent(&key.target_node)
46 }
47}
48
49impl<'a> From<&'a Reference> for ReferenceKey<&'a Identifier, &'a Identifier> {
50 fn from(value: &'a Reference) -> Self {
51 Self {
52 reference_type: (&value.reference_type).into_node_id_ref(),
53 target_node: (&value.target_node).into_node_id_ref(),
54 }
55 }
56}
57
58#[derive(PartialEq, Eq, Clone, Debug, Hash)]
59pub struct ReferenceRef<'a> {
61 pub reference_type: &'a NodeId,
63 pub target_node: &'a NodeId,
65 pub direction: ReferenceDirection,
67}
68
69#[derive(Debug, Default)]
73pub struct References {
75 by_source: HashMap<NodeId, HashSet<Reference>>,
77 by_target: HashMap<NodeId, HashSet<Reference>>,
79}
80
81impl References {
82 pub fn new() -> Self {
84 Self {
85 by_source: HashMap::new(),
86 by_target: HashMap::new(),
87 }
88 }
89
90 pub fn insert<'a, S>(
92 &mut self,
93 source: &NodeId,
94 references: &'a [(&'a NodeId, &S, ReferenceDirection)],
95 ) where
96 S: Into<NodeId> + Clone,
97 {
98 for (target, typ, direction) in references {
99 let typ: NodeId = (*typ).clone().into();
100 match direction {
101 ReferenceDirection::Forward => self.insert_reference(source, target, typ),
102 ReferenceDirection::Inverse => self.insert_reference(target, source, typ),
103 }
104 }
105 }
106
107 pub fn insert_reference(
109 &mut self,
110 source_node: &NodeId,
111 target_node: &NodeId,
112 reference_type: impl Into<NodeId>,
113 ) {
114 if source_node == target_node {
115 panic!("Node id from == node id to {source_node}, self reference is not allowed");
116 }
117
118 let forward_refs = match self.by_source.get_mut(source_node) {
119 Some(r) => r,
120 None => self.by_source.entry(source_node.clone()).or_default(),
121 };
122
123 let reference_type = reference_type.into();
124
125 if !forward_refs.insert(Reference {
126 reference_type: reference_type.clone(),
127 target_node: target_node.clone(),
128 }) {
129 return;
131 }
132
133 let inverse_refs = match self.by_target.get_mut(target_node) {
134 Some(r) => r,
135 None => self.by_target.entry(target_node.clone()).or_default(),
136 };
137
138 inverse_refs.insert(Reference {
139 reference_type,
140 target_node: source_node.clone(),
141 });
142 }
143
144 pub fn insert_references<'a>(
146 &mut self,
147 references: impl Iterator<Item = (&'a NodeId, &'a NodeId, impl Into<NodeId>)>,
148 ) {
149 for (source, target, typ) in references {
150 self.insert_reference(source, target, typ);
151 }
152 }
153
154 pub fn import_reference(&mut self, source_node: NodeId, rf: ImportedReference) {
156 if source_node == rf.target_id {
157 panic!("Node id from == node id to {source_node}, self reference is not allowed");
158 }
159
160 let mut source = source_node;
161 let mut target = rf.target_id;
162 if !rf.is_forward {
163 (source, target) = (target, source);
164 }
165
166 let forward_refs = match self.by_source.get_mut(&source) {
167 Some(r) => r,
168 None => self.by_source.entry(source.clone()).or_default(),
169 };
170
171 if !forward_refs.insert(Reference {
172 reference_type: rf.type_id.clone(),
173 target_node: target.clone(),
174 }) {
175 return;
177 }
178
179 let inverse_refs = match self.by_target.get_mut(&target) {
180 Some(r) => r,
181 None => self.by_target.entry(target).or_default(),
182 };
183
184 inverse_refs.insert(Reference {
185 reference_type: rf.type_id,
186 target_node: source,
187 });
188 }
189
190 pub fn delete_reference<'a>(
192 &mut self,
193 source_node: impl IntoNodeIdRef<'a>,
194 target_node: impl IntoNodeIdRef<'a>,
195 reference_type: impl IntoNodeIdRef<'a>,
196 ) -> bool {
197 let mut found = false;
198 let reference_type = reference_type.into_node_id_ref();
199 let source_node = source_node.into_node_id_ref();
200 let target_node = target_node.into_node_id_ref();
201 let rf = ReferenceKey {
202 reference_type,
203 target_node,
204 };
205 found |= self
206 .by_source
207 .get_mut(&source_node)
208 .map(|f| f.remove(&rf))
209 .unwrap_or_default();
210
211 let rf = ReferenceKey {
212 reference_type,
213 target_node: source_node,
214 };
215
216 found |= self
217 .by_target
218 .get_mut(&target_node)
219 .map(|f| f.remove(&rf))
220 .unwrap_or_default();
221
222 found
223 }
224
225 pub fn delete_node_references<'a>(
230 &mut self,
231 source_node: impl IntoNodeIdRef<'a>,
232 delete_target_references: bool,
233 ) -> bool {
234 let mut found = false;
235 let source_node = source_node.into_node_id_ref();
236 let source = self.by_source.remove(&source_node);
237 found |= source.is_some();
238 if delete_target_references {
239 for rf in source.into_iter().flatten() {
240 if let Some(rec) = self.by_target.get_mut(&rf.target_node) {
241 rec.remove(&ReferenceKey {
242 reference_type: (&rf.reference_type).into_node_id_ref(),
243 target_node: source_node,
244 });
245 }
246 }
247 }
248
249 let target = self.by_target.remove(&source_node);
250 found |= target.is_some();
251
252 if delete_target_references {
253 for rf in target.into_iter().flatten() {
254 if let Some(rec) = self.by_source.get_mut(&rf.target_node) {
255 rec.remove(&ReferenceKey {
256 reference_type: (&rf.reference_type).into_node_id_ref(),
257 target_node: source_node,
258 });
259 }
260 }
261 }
262
263 found
264 }
265
266 pub fn has_reference<'a>(
268 &self,
269 source_node: impl IntoNodeIdRef<'a>,
270 target_node: impl IntoNodeIdRef<'a>,
271 reference_type: impl IntoNodeIdRef<'a>,
272 ) -> bool {
273 let reference_type = reference_type.into_node_id_ref();
274 let target_node = target_node.into_node_id_ref();
275 self.by_source
276 .get(&source_node.into_node_id_ref())
277 .map(|n| {
278 n.contains(&ReferenceKey {
279 reference_type,
280 target_node,
281 })
282 })
283 .unwrap_or_default()
284 }
285
286 pub fn find_references<'a: 'b, 'b>(
288 &'a self,
289 source_node: impl IntoNodeIdRef<'b>,
290 filter: Option<(impl Into<NodeId>, bool)>,
291 type_tree: &'b dyn TypeTree,
292 direction: BrowseDirection,
293 ) -> impl Iterator<Item = ReferenceRef<'a>> + 'b {
294 ReferenceIterator::new(
295 source_node.into_node_id_ref(),
296 direction,
297 self,
298 filter.map(|f| (f.0.into(), f.1)),
299 type_tree,
300 )
301 }
302}
303
304struct ReferenceIterator<'a, 'b> {
306 filter: Option<(NodeId, bool)>,
307 type_tree: &'b dyn TypeTree,
308 iter_s: Option<hashbrown::hash_set::Iter<'a, Reference>>,
309 iter_t: Option<hashbrown::hash_set::Iter<'a, Reference>>,
310}
311
312impl<'a> Iterator for ReferenceIterator<'a, '_> {
313 type Item = ReferenceRef<'a>;
314
315 fn next(&mut self) -> Option<Self::Item> {
316 loop {
317 let inner = self.next_inner()?;
318
319 if let Some(filter) = &self.filter {
320 if !filter.1 && inner.reference_type != &filter.0
321 || filter.1
322 && !self
323 .type_tree
324 .is_subtype_of(inner.reference_type, &filter.0)
325 {
326 continue;
327 }
328 }
329
330 break Some(inner);
331 }
332 }
333
334 fn size_hint(&self) -> (usize, Option<usize>) {
335 let mut lower = 0;
336 let mut upper = None;
337 if let Some(iter_s) = &self.iter_s {
338 let (lower_i, upper_i) = iter_s.size_hint();
339 lower = lower_i;
340 upper = upper_i;
341 }
342
343 if let Some(iter_t) = &self.iter_t {
344 let (lower_i, upper_i) = iter_t.size_hint();
345 lower += lower_i;
346 upper = match (upper, upper_i) {
347 (Some(l), Some(r)) => Some(l + r),
348 _ => None,
349 }
350 }
351
352 (lower, upper)
353 }
354}
355
356impl<'a, 'b> ReferenceIterator<'a, 'b> {
357 fn new<R: IdentifierRef + 'b>(
358 source_node: NodeIdRef<R>,
359 direction: BrowseDirection,
360 references: &'a References,
361 filter: Option<(NodeId, bool)>,
362 type_tree: &'b dyn TypeTree,
363 ) -> Self {
364 Self {
365 filter,
366 type_tree,
367 iter_s: matches!(direction, BrowseDirection::Both | BrowseDirection::Forward)
368 .then(|| references.by_source.get(&source_node))
369 .flatten()
370 .map(|r| r.iter()),
371 iter_t: matches!(direction, BrowseDirection::Both | BrowseDirection::Inverse)
372 .then(|| references.by_target.get(&source_node))
373 .flatten()
374 .map(|r| r.iter()),
375 }
376 }
377
378 fn next_inner(&mut self) -> Option<ReferenceRef<'a>> {
379 if let Some(iter_s) = &mut self.iter_s {
380 match iter_s.next() {
381 Some(r) => {
382 return Some(ReferenceRef {
383 reference_type: &r.reference_type,
384 target_node: &r.target_node,
385 direction: ReferenceDirection::Forward,
386 })
387 }
388 None => self.iter_s = None,
389 }
390 }
391
392 if let Some(iter_t) = &mut self.iter_t {
393 match iter_t.next() {
394 Some(r) => {
395 return Some(ReferenceRef {
396 reference_type: &r.reference_type,
397 target_node: &r.target_node,
398 direction: ReferenceDirection::Inverse,
399 })
400 }
401 None => self.iter_t = None,
402 }
403 }
404
405 None
406 }
407}