Skip to main content

component_tree/
component_tree.rs

1// Draws the component tree of a reference device with box-drawing characters:
2// every component with its type and local id, plus each component's visible
3// properties with their type and current value.
4
5use opendaq::{Component, CoreType, Folder, Instance, Property, PropertyObject, Value};
6
7/// Readable type name for a component, e.g. "Channel" or "FunctionBlock".
8fn type_label(component: &Component) -> String {
9    component
10        .component_kind()
11        .map_or_else(|| "Component".to_string(), |kind| format!("{kind:?}"))
12}
13
14/// Printable value of `property` on `object`.  `property_value` already
15/// returns scalars as native Rust values; structured ones come back as
16/// wrappers and are shown as "<Type>" instead.
17fn property_value_string(object: &PropertyObject, property: &Property) -> opendaq::Result<String> {
18    Ok(match property.value_type()? {
19        CoreType::Bool
20        | CoreType::Int
21        | CoreType::Float
22        | CoreType::String
23        | CoreType::Ratio
24        | CoreType::ComplexNumber => match object.property_value(&property.name()?)? {
25            Value::Str(text) => format!("{text:?}"),
26            value => value.to_string(),
27        },
28        other => format!("<{other:?}>"),
29    })
30}
31
32/// Print the visible properties of `component`, each line indented with `prefix`.
33fn draw_properties(component: &Component, prefix: &str) -> opendaq::Result<()> {
34    for property in component.visible_properties()? {
35        println!(
36            "{prefix}• {} : {:?} = {}",
37            property.name()?,
38            property.value_type()?,
39            property_value_string(component, &property)?
40        );
41    }
42    Ok(())
43}
44
45/// The immediate child components of `component` if it is a folder.
46fn children(component: &Component) -> opendaq::Result<Vec<Component>> {
47    if component.is_a::<Folder>() {
48        component.cast::<Folder>()?.items()
49    } else {
50        Ok(Vec::new())
51    }
52}
53
54fn draw_children(component: &Component, prefix: &str) -> opendaq::Result<()> {
55    let kids = children(component)?;
56    for (index, child) in kids.iter().enumerate() {
57        let last = index + 1 == kids.len();
58        let child_prefix = format!("{prefix}{}", if last { "   " } else { "│  " });
59        println!(
60            "{prefix}{}{} : {} ({})",
61            if last { "└─ " } else { "├─ " },
62            child.name()?,
63            type_label(child),
64            child.local_id()?
65        );
66        draw_properties(child, &child_prefix)?;
67        draw_children(child, &child_prefix)?;
68    }
69    Ok(())
70}
71
72fn main() -> opendaq::Result<()> {
73    let instance = Instance::new()?;
74    instance.add_device("daqref://device0")?;
75
76    let root = instance.root_device()?.expect("root device");
77    println!(
78        "{} : {} ({})",
79        root.name()?,
80        type_label(&root),
81        root.local_id()?
82    );
83    draw_properties(&root, "")?;
84    draw_children(&root, "")
85}