opcua_types/
event_field.rs

1//! Core logic for reading Variant values from an event.
2
3use std::collections::HashMap;
4
5use crate::{Array, AttributeId, IntoVariant, NumericRange, QualifiedName, Variant, VariantType};
6
7/// Trait implemented by any type that can be a field in an event.
8pub trait EventField {
9    /// Get the variant representation of this field, using the given index range.
10    ///
11    /// # Arguments
12    ///
13    ///  * `attribute_id` - the attribute to get. Should be either `NodeId` or `Value`.
14    ///  * `index_range` - the range of the value to get.
15    ///  * `remaining_path` - the remaining path to the actual value to retrieve.
16    fn get_value(
17        &self,
18        attribute_id: AttributeId,
19        index_range: &NumericRange,
20        remaining_path: &[QualifiedName],
21    ) -> Variant;
22}
23
24impl<T> EventField for T
25where
26    T: IntoVariant + Clone,
27{
28    fn get_value(
29        &self,
30        attribute_id: AttributeId,
31        index_range: &NumericRange,
32        remaining_path: &[QualifiedName],
33    ) -> Variant {
34        if !remaining_path.is_empty()
35            || attribute_id != AttributeId::Value
36            || !matches!(index_range, NumericRange::None)
37        {
38            return Variant::Empty;
39        }
40        let val: Variant = self.clone().into_variant();
41        val.range_of_owned(index_range).unwrap_or(Variant::Empty)
42    }
43}
44
45impl<T> EventField for Option<T>
46where
47    T: EventField,
48{
49    fn get_value(
50        &self,
51        attribute_id: AttributeId,
52        index_range: &NumericRange,
53        remaining_path: &[QualifiedName],
54    ) -> Variant {
55        let Some(val) = self.as_ref() else {
56            return Variant::Empty;
57        };
58        val.get_value(attribute_id, index_range, remaining_path)
59    }
60}
61
62impl<T> EventField for Vec<T>
63where
64    T: EventField + Clone + VariantType,
65{
66    fn get_value(
67        &self,
68        attribute_id: AttributeId,
69        index_range: &NumericRange,
70        remaining_path: &[QualifiedName],
71    ) -> Variant {
72        if !remaining_path.is_empty() {
73            return Variant::Empty;
74        }
75
76        let values: Vec<_> = match index_range {
77            NumericRange::None => self
78                .iter()
79                .map(|v| v.get_value(attribute_id, &NumericRange::None, &[]))
80                .collect(),
81            NumericRange::Index(i) => {
82                return self.get((*i) as usize).cloned().get_value(
83                    attribute_id,
84                    &NumericRange::None,
85                    &[],
86                );
87            }
88            NumericRange::Range(s, e) => {
89                if e <= s {
90                    return Variant::Empty;
91                }
92                let Some(r) = self.get(((*s) as usize)..((*e) as usize)) else {
93                    return Variant::Empty;
94                };
95                r.iter()
96                    .map(|v| v.get_value(attribute_id, &NumericRange::None, &[]))
97                    .collect()
98            }
99            NumericRange::MultipleRanges(r) => {
100                let mut values = Vec::new();
101                for range in r {
102                    match range {
103                        NumericRange::Index(i) => {
104                            values.push(self.get((*i) as usize).cloned().get_value(
105                                attribute_id,
106                                &NumericRange::None,
107                                &[],
108                            ));
109                        }
110                        NumericRange::Range(s, e) => {
111                            if e <= s {
112                                return Variant::Empty;
113                            }
114                            let Some(r) = self.get(((*s) as usize)..((*e) as usize)) else {
115                                continue;
116                            };
117                            values.extend(
118                                r.iter()
119                                    .map(|v| v.get_value(attribute_id, &NumericRange::None, &[])),
120                            )
121                        }
122                        _ => return Variant::Empty,
123                    }
124                }
125                values
126            }
127        };
128
129        let Ok(arr) = Array::new(T::variant_type_id(), values) else {
130            return Variant::Empty;
131        };
132        Variant::Array(Box::new(arr))
133    }
134}
135
136impl EventField for Variant {
137    fn get_value(
138        &self,
139        attribute_id: AttributeId,
140        index_range: &NumericRange,
141        remaining_path: &[QualifiedName],
142    ) -> Variant {
143        if !remaining_path.is_empty() || attribute_id != AttributeId::Value {
144            return Variant::Empty;
145        }
146        self.clone()
147            .range_of_owned(index_range)
148            .unwrap_or(Variant::Empty)
149    }
150}
151
152impl EventField for NumericRange {
153    fn get_value(
154        &self,
155        attribute_id: AttributeId,
156        index_range: &NumericRange,
157        remaining_path: &[QualifiedName],
158    ) -> Variant {
159        if !remaining_path.is_empty() || attribute_id != AttributeId::Value {
160            return Variant::Empty;
161        }
162        let val: Variant = self.to_string().into();
163        val.range_of_owned(index_range).unwrap_or(Variant::Empty)
164    }
165}
166
167#[derive(Debug)]
168/// Struct for an event field placeholder, i.e. a dynamic list of fields.
169pub struct PlaceholderEventField<T> {
170    items: HashMap<QualifiedName, T>,
171}
172
173impl<T> Default for PlaceholderEventField<T> {
174    fn default() -> Self {
175        Self {
176            items: Default::default(),
177        }
178    }
179}
180
181impl<T> PlaceholderEventField<T> {
182    /// Create a new empty placeholder field.
183    pub fn new() -> Self {
184        Self {
185            items: HashMap::new(),
186        }
187    }
188
189    /// Get the field given by `name`.
190    pub fn get_field(&self, name: &QualifiedName) -> Option<&T> {
191        self.items.get(name)
192    }
193
194    /// Get a mutable reference to the field given by `name`.
195    pub fn get_field_mut(&mut self, name: &QualifiedName) -> Option<&mut T> {
196        self.items.get_mut(name)
197    }
198
199    /// Remove the field given by `name`.
200    pub fn remove_field(&mut self, name: &QualifiedName) -> Option<T> {
201        self.items.remove(name)
202    }
203
204    /// Insert `field` with key `name`.
205    pub fn insert_field(&mut self, name: QualifiedName, field: T) -> Option<T> {
206        self.items.insert(name, field)
207    }
208
209    /// Get a mutable reference to the inner items map.
210    pub fn items_mut(&mut self) -> &mut HashMap<QualifiedName, T> {
211        &mut self.items
212    }
213
214    /// Get a reference to the inner items map.
215    pub fn items(&self) -> &HashMap<QualifiedName, T> {
216        &self.items
217    }
218}
219
220impl<T: EventField> PlaceholderEventField<T> {
221    /// Try to get the inner event value given by `key`.
222    pub fn try_get_value(
223        &self,
224        key: &QualifiedName,
225        attribute_id: AttributeId,
226        index_range: &NumericRange,
227        remaining_path: &[QualifiedName],
228    ) -> Option<Variant> {
229        let field = self.get_field(key)?;
230        Some(field.get_value(attribute_id, index_range, remaining_path))
231    }
232}