1use std::convert::TryFrom;
6
7use crate::types::{
8 attribute::AttributeId,
9 node_ids::ObjectId,
10 service_types::{
11 AttributeOperand, ContentFilter, ContentFilterElement, ElementOperand, FilterOperator,
12 LiteralOperand, SimpleAttributeOperand,
13 },
14 status_code::StatusCode,
15 DecodingOptions, ExtensionObject, NodeId, QualifiedName, UAString, Variant,
16};
17
18#[derive(PartialEq)]
19pub enum OperandType {
20 ElementOperand,
21 LiteralOperand,
22 AttributeOperand,
23 SimpleAttributeOperand,
24}
25
26pub enum Operand {
27 ElementOperand(ElementOperand),
28 LiteralOperand(LiteralOperand),
29 AttributeOperand(AttributeOperand),
30 SimpleAttributeOperand(SimpleAttributeOperand),
31}
32
33impl From<i8> for LiteralOperand {
34 fn from(v: i8) -> Self {
35 Self::from(Variant::from(v))
36 }
37}
38
39impl From<u8> for LiteralOperand {
40 fn from(v: u8) -> Self {
41 Self::from(Variant::from(v))
42 }
43}
44
45impl From<i16> for LiteralOperand {
46 fn from(v: i16) -> Self {
47 Self::from(Variant::from(v))
48 }
49}
50
51impl From<u16> for LiteralOperand {
52 fn from(v: u16) -> Self {
53 Self::from(Variant::from(v))
54 }
55}
56
57impl From<i32> for LiteralOperand {
58 fn from(v: i32) -> Self {
59 Self::from(Variant::from(v))
60 }
61}
62
63impl From<u32> for LiteralOperand {
64 fn from(v: u32) -> Self {
65 Self::from(Variant::from(v))
66 }
67}
68
69impl From<f32> for LiteralOperand {
70 fn from(v: f32) -> Self {
71 Self::from(Variant::from(v))
72 }
73}
74
75impl From<f64> for LiteralOperand {
76 fn from(v: f64) -> Self {
77 Self::from(Variant::from(v))
78 }
79}
80
81impl From<bool> for LiteralOperand {
82 fn from(v: bool) -> Self {
83 Self::from(Variant::from(v))
84 }
85}
86
87impl From<&str> for LiteralOperand {
88 fn from(v: &str) -> Self {
89 Self::from(Variant::from(v))
90 }
91}
92
93impl From<()> for LiteralOperand {
94 fn from(_v: ()) -> Self {
95 Self::from(Variant::from(()))
96 }
97}
98
99impl From<Variant> for LiteralOperand {
100 fn from(v: Variant) -> Self {
101 LiteralOperand { value: v }
102 }
103}
104
105impl TryFrom<&ExtensionObject> for Operand {
106 type Error = StatusCode;
107
108 fn try_from(v: &ExtensionObject) -> Result<Self, Self::Error> {
109 let object_id = v
110 .object_id()
111 .map_err(|_| StatusCode::BadFilterOperandInvalid)?;
112 let decoding_options = DecodingOptions::minimal();
113 let operand = match object_id {
114 ObjectId::ElementOperand_Encoding_DefaultBinary => {
115 Operand::ElementOperand(v.decode_inner::<ElementOperand>(&decoding_options)?)
116 }
117 ObjectId::LiteralOperand_Encoding_DefaultBinary => {
118 Operand::LiteralOperand(v.decode_inner::<LiteralOperand>(&decoding_options)?)
119 }
120 ObjectId::AttributeOperand_Encoding_DefaultBinary => {
121 Operand::AttributeOperand(v.decode_inner::<AttributeOperand>(&decoding_options)?)
122 }
123 ObjectId::SimpleAttributeOperand_Encoding_DefaultBinary => {
124 Operand::SimpleAttributeOperand(
125 v.decode_inner::<SimpleAttributeOperand>(&decoding_options)?,
126 )
127 }
128 _ => {
129 return Err(StatusCode::BadFilterOperandInvalid);
130 }
131 };
132 Ok(operand)
133 }
134}
135
136impl From<&Operand> for ExtensionObject {
137 fn from(v: &Operand) -> Self {
138 match v {
139 Operand::ElementOperand(ref op) => {
140 ExtensionObject::from_encodable(ObjectId::ElementOperand_Encoding_DefaultBinary, op)
141 }
142 Operand::LiteralOperand(ref op) => {
143 ExtensionObject::from_encodable(ObjectId::LiteralOperand_Encoding_DefaultBinary, op)
144 }
145 Operand::AttributeOperand(ref op) => ExtensionObject::from_encodable(
146 ObjectId::AttributeOperand_Encoding_DefaultBinary,
147 op,
148 ),
149 Operand::SimpleAttributeOperand(ref op) => ExtensionObject::from_encodable(
150 ObjectId::SimpleAttributeOperand_Encoding_DefaultBinary,
151 op,
152 ),
153 }
154 }
155}
156
157impl From<Operand> for ExtensionObject {
158 fn from(v: Operand) -> Self {
159 Self::from(&v)
160 }
161}
162
163impl From<(FilterOperator, Vec<Operand>)> for ContentFilterElement {
164 fn from(v: (FilterOperator, Vec<Operand>)) -> ContentFilterElement {
165 ContentFilterElement {
166 filter_operator: v.0,
167 filter_operands: Some(v.1.iter().map(|op| op.into()).collect()),
168 }
169 }
170}
171
172impl From<ElementOperand> for Operand {
173 fn from(v: ElementOperand) -> Operand {
174 Operand::ElementOperand(v)
175 }
176}
177
178impl From<LiteralOperand> for Operand {
179 fn from(v: LiteralOperand) -> Self {
180 Operand::LiteralOperand(v)
181 }
182}
183
184impl From<SimpleAttributeOperand> for Operand {
185 fn from(v: SimpleAttributeOperand) -> Self {
186 Operand::SimpleAttributeOperand(v)
187 }
188}
189
190impl Operand {
191 pub fn element(index: u32) -> Operand {
192 ElementOperand { index }.into()
193 }
194
195 pub fn literal<T>(literal: T) -> Operand
196 where
197 T: Into<LiteralOperand>,
198 {
199 Operand::LiteralOperand(literal.into())
200 }
201
202 pub fn simple_attribute<T>(
204 type_definition_id: T,
205 browse_path: &str,
206 attribute_id: AttributeId,
207 index_range: UAString,
208 ) -> Operand
209 where
210 T: Into<NodeId>,
211 {
212 SimpleAttributeOperand::new(type_definition_id, browse_path, attribute_id, index_range)
213 .into()
214 }
215
216 pub fn operand_type(&self) -> OperandType {
217 match self {
218 Operand::ElementOperand(_) => OperandType::ElementOperand,
219 Operand::LiteralOperand(_) => OperandType::LiteralOperand,
220 Operand::AttributeOperand(_) => OperandType::AttributeOperand,
221 Operand::SimpleAttributeOperand(_) => OperandType::SimpleAttributeOperand,
222 }
223 }
224
225 pub fn is_element(&self) -> bool {
226 self.operand_type() == OperandType::ElementOperand
227 }
228
229 pub fn is_literal(&self) -> bool {
230 self.operand_type() == OperandType::LiteralOperand
231 }
232
233 pub fn is_attribute(&self) -> bool {
234 self.operand_type() == OperandType::AttributeOperand
235 }
236
237 pub fn is_simple_attribute(&self) -> bool {
238 self.operand_type() == OperandType::SimpleAttributeOperand
239 }
240}
241
242pub struct ContentFilterBuilder {
250 elements: Vec<ContentFilterElement>,
251}
252
253impl Default for ContentFilterBuilder {
254 fn default() -> Self {
255 ContentFilterBuilder {
256 elements: Vec::with_capacity(20),
257 }
258 }
259}
260
261impl ContentFilterBuilder {
262 pub fn new() -> Self {
263 Self::default()
264 }
265
266 fn add_element(
267 mut self,
268 filter_operator: FilterOperator,
269 filter_operands: Vec<Operand>,
270 ) -> Self {
271 let filter_operands = filter_operands.iter().map(ExtensionObject::from).collect();
272 self.elements.push(ContentFilterElement {
273 filter_operator,
274 filter_operands: Some(filter_operands),
275 });
276 self
277 }
278
279 pub fn eq<T, S>(self, o1: T, o2: S) -> Self
280 where
281 T: Into<Operand>,
282 S: Into<Operand>,
283 {
284 self.add_element(FilterOperator::Equals, vec![o1.into(), o2.into()])
285 }
286
287 pub fn null<T>(self, o1: T) -> Self
288 where
289 T: Into<Operand>,
290 {
291 self.add_element(FilterOperator::IsNull, vec![o1.into()])
292 }
293
294 pub fn gt<T, S>(self, o1: T, o2: S) -> Self
295 where
296 T: Into<Operand>,
297 S: Into<Operand>,
298 {
299 self.add_element(FilterOperator::GreaterThan, vec![o1.into(), o2.into()])
300 }
301
302 pub fn lt<T, S>(self, o1: T, o2: S) -> Self
303 where
304 T: Into<Operand>,
305 S: Into<Operand>,
306 {
307 self.add_element(FilterOperator::LessThan, vec![o1.into(), o2.into()])
308 }
309
310 pub fn gte<T, S>(self, o1: T, o2: S) -> Self
311 where
312 T: Into<Operand>,
313 S: Into<Operand>,
314 {
315 self.add_element(
316 FilterOperator::GreaterThanOrEqual,
317 vec![o1.into(), o2.into()],
318 )
319 }
320
321 pub fn lte<T, S>(self, o1: T, o2: S) -> Self
322 where
323 T: Into<Operand>,
324 S: Into<Operand>,
325 {
326 self.add_element(FilterOperator::LessThanOrEqual, vec![o1.into(), o2.into()])
327 }
328
329 pub fn like<T, S>(self, o1: T, o2: S) -> Self
330 where
331 T: Into<Operand>,
332 S: Into<Operand>,
333 {
334 self.add_element(FilterOperator::Like, vec![o1.into(), o2.into()])
335 }
336
337 pub fn not<T>(self, o1: T) -> Self
338 where
339 T: Into<Operand>,
340 {
341 self.add_element(FilterOperator::Not, vec![o1.into()])
342 }
343
344 pub fn between<T, S, U>(self, o1: T, o2: S, o3: U) -> Self
345 where
346 T: Into<Operand>,
347 S: Into<Operand>,
348 U: Into<Operand>,
349 {
350 self.add_element(
351 FilterOperator::Between,
352 vec![o1.into(), o2.into(), o3.into()],
353 )
354 }
355
356 pub fn in_list<T, S>(self, o1: T, list_items: Vec<S>) -> Self
357 where
358 T: Into<Operand>,
359 S: Into<Operand>,
360 {
361 let mut filter_operands = Vec::with_capacity(list_items.len() + 1);
363 filter_operands.push(o1.into());
364 list_items.into_iter().for_each(|list_item| {
365 filter_operands.push(list_item.into());
366 });
367 self.add_element(FilterOperator::InList, filter_operands)
368 }
369
370 pub fn and<T, S>(self, o1: T, o2: S) -> Self
371 where
372 T: Into<Operand>,
373 S: Into<Operand>,
374 {
375 self.add_element(FilterOperator::And, vec![o1.into(), o2.into()])
376 }
377
378 pub fn or<T, S>(self, o1: T, o2: S) -> Self
379 where
380 T: Into<Operand>,
381 S: Into<Operand>,
382 {
383 self.add_element(FilterOperator::Or, vec![o1.into(), o2.into()])
384 }
385
386 pub fn cast<T, S>(self, o1: T, o2: S) -> Self
387 where
388 T: Into<Operand>,
389 S: Into<Operand>,
390 {
391 self.add_element(FilterOperator::Cast, vec![o1.into(), o2.into()])
392 }
393
394 pub fn bitwise_and<T, S>(self, o1: T, o2: S) -> Self
395 where
396 T: Into<Operand>,
397 S: Into<Operand>,
398 {
399 self.add_element(FilterOperator::BitwiseAnd, vec![o1.into(), o2.into()])
400 }
401
402 pub fn bitwise_or<T, S>(self, o1: T, o2: S) -> Self
403 where
404 T: Into<Operand>,
405 S: Into<Operand>,
406 {
407 self.add_element(FilterOperator::BitwiseOr, vec![o1.into(), o2.into()])
408 }
409
410 pub fn build(self) -> ContentFilter {
411 ContentFilter {
412 elements: Some(self.elements),
413 }
414 }
415}
416
417impl SimpleAttributeOperand {
418 pub fn new<T>(
419 type_definition_id: T,
420 browse_path: &str,
421 attribute_id: AttributeId,
422 index_range: UAString,
423 ) -> Self
424 where
425 T: Into<NodeId>,
426 {
427 const ESCAPE_PATTERN: &str = "###!!!###@@@$$$$";
429 let browse_path = browse_path.replace(r"\/", ESCAPE_PATTERN);
431 let browse_path = browse_path
435 .split('/')
436 .map(|s| QualifiedName::new(0, s.replace(ESCAPE_PATTERN, "/")))
437 .collect();
438 SimpleAttributeOperand {
439 type_definition_id: type_definition_id.into(),
440 browse_path: Some(browse_path),
441 attribute_id: attribute_id as u32,
442 index_range,
443 }
444 }
445}