anathema_widgets/query/
components.rs

1use std::ops::ControlFlow;
2
3use anathema_value_resolver::{AttributeStorage, Attributes};
4
5use super::{Chain, Filter, Nodes, Query, QueryValue};
6use crate::nodes::component::Component;
7use crate::{WidgetId, WidgetKind};
8
9pub struct Components<'children, 'tree, 'bp> {
10    pub(super) elements: &'children mut Nodes<'tree, 'bp>,
11}
12
13impl<'children, 'tree, 'bp> Components<'children, 'tree, 'bp> {
14    pub fn by_name<'a>(&mut self, name: &'a str) -> ComponentQuery<'_, 'tree, 'bp, Kind<'a>> {
15        self.make_query(Kind::ByName(name))
16    }
17
18    pub fn by_attribute<'a>(
19        &mut self,
20        key: &'a str,
21        value: impl Into<QueryValue<'a>>,
22    ) -> ComponentQuery<'_, 'tree, 'bp, Kind<'a>> {
23        self.make_query(Kind::ByAttribute(key, value.into()))
24    }
25
26    fn make_query<'a>(&mut self, kind: Kind<'a>) -> ComponentQuery<'_, 'tree, 'bp, Kind<'a>> {
27        ComponentQuery {
28            query: Query {
29                filter: kind,
30                elements: self.elements,
31            },
32        }
33    }
34}
35
36pub struct ComponentQuery<'el, 'tree, 'bp, T>
37where
38    T: Filter<'bp, Kind = Component<'bp>> + Copy,
39{
40    query: Query<'el, 'tree, 'bp, T, Component<'bp>>,
41}
42
43impl<'el, 'tree, 'bp, T> ComponentQuery<'el, 'tree, 'bp, T>
44where
45    T: Filter<'bp, Kind = Component<'bp>> + Copy,
46{
47    pub fn by_name(self, name: &str) -> ComponentQuery<'el, 'tree, 'bp, Chain<T, Kind<'_>>> {
48        ComponentQuery {
49            query: Query {
50                filter: Chain::new(self.query.filter, Kind::ByName(name)),
51                elements: self.query.elements,
52            },
53        }
54    }
55
56    pub fn by_attribute<'a>(
57        self,
58        key: &'a str,
59        value: impl Into<QueryValue<'a>>,
60    ) -> ComponentQuery<'el, 'tree, 'bp, Chain<T, Kind<'a>>> {
61        ComponentQuery {
62            query: Query {
63                filter: Chain::new(self.query.filter, Kind::ByAttribute(key, value.into())),
64                elements: self.query.elements,
65            },
66        }
67    }
68
69    pub fn first<F, U>(self, mut f: F) -> Option<U>
70    where
71        F: FnMut(WidgetId, &mut Component<'_>, &mut Attributes<'_>) -> U,
72    {
73        match self.query(&mut f, false) {
74            ControlFlow::Continue(_) => None,
75            ControlFlow::Break(val) => Some(val),
76        }
77    }
78
79    pub fn each<F>(self, mut f: F)
80    where
81        F: FnMut(WidgetId, &mut Component<'_>, &mut Attributes<'_>),
82    {
83        _ = self.query(&mut f, true);
84    }
85
86    fn query<F, U>(self, f: &mut F, continuous: bool) -> ControlFlow<U>
87    where
88        F: FnMut(WidgetId, &mut Component<'_>, &mut Attributes<'_>) -> U,
89    {
90        let ret_val = self.query.elements.children.for_each(|_path, container, children| {
91            if let WidgetKind::Component(ref mut component) = container.kind {
92                if self.query.filter.filter(component, self.query.elements.attributes) {
93                    let attributes = self.query.elements.attributes.get_mut(component.widget_id);
94                    let ret_val = f(component.widget_id, component, attributes);
95
96                    if !continuous {
97                        return ControlFlow::Break(ret_val);
98                    }
99                }
100            }
101
102            let mut elements = Nodes::new(
103                children,
104                self.query.elements.attributes,
105                self.query.elements.needs_layout,
106            );
107
108            let query = ComponentQuery {
109                query: Query {
110                    elements: &mut elements,
111                    filter: self.query.filter,
112                },
113            };
114
115            query.query(f, continuous)
116        });
117
118        match ret_val {
119            Some(val) => ControlFlow::Break(val),
120            None => ControlFlow::Continue(()),
121        }
122    }
123}
124
125// -----------------------------------------------------------------------------
126//   - Query kind -
127// -----------------------------------------------------------------------------
128#[derive(Debug, Copy, Clone)]
129pub enum Kind<'a> {
130    ByName(&'a str),
131    ByAttribute(&'a str, QueryValue<'a>),
132}
133
134impl<'bp> Filter<'bp> for Kind<'_> {
135    type Kind = Component<'bp>;
136
137    fn filter(&self, el: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool {
138        match self {
139            Kind::ByName(name) => el.name == *name,
140            Kind::ByAttribute(key, value) => {
141                let attribs = attributes.get(el.widget_id);
142                attribs.get(key).map(|attribute| value.eq(attribute)).unwrap_or(false)
143            }
144        }
145    }
146}