Skip to main content

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