Skip to main content

search_filter/
search_filter.rs

1// Finding components with search filters.
2//
3// The getter methods for a device's tree -- channels, signals, devices,
4// function blocks, and a folder's items -- all come in a `_with` variant that
5// takes an optional search filter.  A filter answers two questions about
6// every component the search walks over: "accept this one into the result?"
7// and "descend into its children?".
8//
9// With no filter the getters return only the immediate, visible children, so
10// `channels()` of the top-level device below finds nothing -- the channels
11// live one device deeper.  A `SearchFilter::recursive` wrapper makes the
12// search descend.
13//
14// Filters compose by construction: `SearchFilter::and`, `SearchFilter::or`,
15// and `SearchFilter::not` take other filters as their arguments.  The
16// recursive wrapper must be the outermost one -- never nest it inside
17// another filter.
18
19use opendaq::{Component, Instance, Interface, SearchFilter, TagsPrivate};
20
21/// Print `components` by their local id under `label`.
22fn show<T: Interface>(label: &str, components: Vec<T>) -> opendaq::Result<()> {
23    let ids = components
24        .iter()
25        .map(|c| c.to_base_object().cast::<Component>()?.local_id())
26        .collect::<opendaq::Result<Vec<_>>>()?;
27    let listing = if ids.is_empty() {
28        "(none)".to_string()
29    } else {
30        ids.join(", ")
31    };
32    println!("{label}\n    => {listing}\n");
33    Ok(())
34}
35
36fn main() -> opendaq::Result<()> {
37    let instance = Instance::new()?;
38    instance.add_device("daqref://device0")?;
39    let root = instance.root_device()?.expect("root device");
40
41    // Give a couple of channels some tags, so the tag filter has something to
42    // match.  (RefCh0 and RefCh1 come from the reference device unlabelled.)
43    let everything = SearchFilter::recursive(&SearchFilter::any()?)?;
44    for channel in root.channels_with(Some(&everything))? {
45        let tags = channel.tags()?.expect("tags").cast::<TagsPrivate>()?;
46        tags.add("analog")?;
47        if channel.local_id()? == "RefCh0" {
48            tags.add("primary")?;
49        }
50    }
51
52    show(
53        "channels, no filter (immediate children only)",
54        root.channels()?,
55    )?;
56
57    show(
58        "channels, recursive(any)",
59        root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::any()?)?))?,
60    )?;
61
62    show(
63        "channels, recursive(id = RefCh1)",
64        root.channels_with(Some(&SearchFilter::recursive(&SearchFilter::local_id(
65            "RefCh1",
66        )?)?))?,
67    )?;
68
69    let ai0_or_ai1 = SearchFilter::or(
70        &SearchFilter::local_id("AI0")?,
71        &SearchFilter::local_id("AI1")?,
72    )?;
73    show(
74        "signals, recursive(id = AI0 OR id = AI1)",
75        root.signals_with(Some(&SearchFilter::recursive(&ai0_or_ai1)?))?,
76    )?;
77
78    let not_ref_ch1 = SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?;
79    show(
80        "channels, recursive(NOT id = RefCh1)",
81        root.channels_with(Some(&SearchFilter::recursive(&not_ref_ch1)?))?,
82    )?;
83
84    let analog_and_not_ref_ch1 = SearchFilter::and(
85        &SearchFilter::required_tags(vec!["analog"])?,
86        &SearchFilter::not(&SearchFilter::local_id("RefCh1")?)?,
87    )?;
88    show(
89        "channels, recursive(tag = analog AND NOT id = RefCh1)",
90        root.channels_with(Some(&SearchFilter::recursive(&analog_and_not_ref_ch1)?))?,
91    )?;
92
93    Ok(())
94}