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#[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}