1use anathema_state::{Color, Hex};
2use anathema_value_resolver::{AttributeStorage, ValueKind};
3
4pub use self::components::Components;
5pub use self::elements::Elements;
6use crate::WidgetTreeView;
7
8mod components;
9mod elements;
10
11pub struct Children<'tree, 'bp>(Nodes<'tree, 'bp>);
12
13impl<'tree, 'bp> Children<'tree, 'bp> {
14 pub fn new(
15 children: WidgetTreeView<'tree, 'bp>,
16 attribute_storage: &'tree mut AttributeStorage<'bp>,
17 needs_layout: &'tree mut bool,
18 ) -> Self {
19 Self(Nodes::new(children, attribute_storage, needs_layout))
20 }
21
22 pub fn elements(&mut self) -> Elements<'_, 'tree, 'bp> {
23 Elements { elements: &mut self.0 }
24 }
25
26 pub fn components(&mut self) -> Components<'_, 'tree, 'bp> {
27 Components { elements: &mut self.0 }
28 }
29
30 pub fn parent_path(&self) -> &[u16] {
31 self.0.children.offset
32 }
33}
34
35#[derive(Debug, Copy, Clone)]
36pub enum QueryValue<'a> {
37 Str(&'a str),
38 Int(i64),
39 Float(f64),
40 Bool(bool),
41 Char(char),
42 Hex(Hex),
43 Color(Color),
44}
45
46impl<'a> From<&'a str> for QueryValue<'a> {
47 fn from(value: &'a str) -> Self {
48 Self::Str(value)
49 }
50}
51
52impl<'a> From<bool> for QueryValue<'a> {
53 fn from(value: bool) -> Self {
54 Self::Bool(value)
55 }
56}
57
58macro_rules! impl_from_int {
59 ($t:ty) => {
60 impl<'a> From<$t> for QueryValue<'a> {
61 fn from(value: $t) -> Self {
62 Self::Int(value as i64)
63 }
64 }
65 };
66}
67
68impl_from_int!(u8);
69impl_from_int!(u16);
70impl_from_int!(u32);
71impl_from_int!(u64);
72impl_from_int!(usize);
73impl_from_int!(i8);
74impl_from_int!(i16);
75impl_from_int!(i32);
76impl_from_int!(i64);
77impl_from_int!(isize);
78
79impl PartialEq<ValueKind<'_>> for QueryValue<'_> {
80 fn eq(&self, other: &ValueKind<'_>) -> bool {
81 match self {
82 QueryValue::Str(lhs) => match other {
83 ValueKind::Str(rhs) => lhs == rhs,
84 _ => false,
85 },
86 QueryValue::Bool(lhs) => match other {
87 ValueKind::Bool(rhs) => lhs == rhs,
88 _ => false,
89 },
90 &QueryValue::Int(lhs) => match other {
91 &ValueKind::Int(rhs) => lhs == rhs,
92 _ => false,
93 },
94 &QueryValue::Float(lhs) => match other {
95 &ValueKind::Float(rhs) => lhs == rhs,
96 _ => false,
97 },
98 &QueryValue::Char(lhs) => match other {
99 &ValueKind::Char(rhs) => lhs == rhs,
100 _ => false,
101 },
102 &QueryValue::Hex(lhs) => match other {
103 &ValueKind::Hex(rhs) => lhs == rhs,
104 _ => false,
105 },
106 &QueryValue::Color(lhs) => match other {
107 &ValueKind::Color(rhs) => lhs == rhs,
108 _ => false,
109 },
110 }
111 }
112}
113
114pub struct Nodes<'tree, 'bp> {
118 children: WidgetTreeView<'tree, 'bp>,
119 attributes: &'tree mut AttributeStorage<'bp>,
120 needs_layout: &'tree mut bool,
121}
122
123impl<'tree, 'bp> Nodes<'tree, 'bp> {
124 pub fn new(
125 children: WidgetTreeView<'tree, 'bp>,
126 attribute_storage: &'tree mut AttributeStorage<'bp>,
127 needs_layout: &'tree mut bool,
128 ) -> Self {
129 Self {
130 children,
131 attributes: attribute_storage,
132 needs_layout,
133 }
134 }
135}
136
137pub struct Query<'el, 'tree, 'bp, F, T>
141where
142 F: Filter<'bp, Kind = T>,
143{
144 filter: F,
145 elements: &'el mut Nodes<'tree, 'bp>,
146}
147
148impl<'el, 'tree, 'bp, F, T> Filter<'bp> for Query<'el, 'tree, 'bp, F, T>
149where
150 F: Filter<'bp, Kind = T>,
151{
152 type Kind = T;
153
154 fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool {
155 self.filter.filter(arg, attributes)
156 }
157}
158
159pub trait Filter<'bp> {
163 type Kind;
164
165 fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool;
166}
167
168#[derive(Debug, Copy, Clone)]
172pub struct Chain<A, B> {
173 a: A,
174 b: B,
175}
176
177impl<A, B> Chain<A, B> {
178 pub fn new(a: A, b: B) -> Self {
179 Self { a, b }
180 }
181}
182
183impl<'bp, A, B> Filter<'bp> for Chain<A, B>
184where
185 A: Filter<'bp>,
186 B: Filter<'bp, Kind = A::Kind>,
187{
188 type Kind = A::Kind;
189
190 fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool {
191 self.a.filter(arg, attributes) && self.b.filter(arg, attributes)
192 }
193}
194
195#[cfg(test)]
196mod test {
197 use super::*;
198
199 #[test]
200 fn filter_by_tag() {
201 let tpl = "
202 many
203 many
204 text '1'
205 text '2'
206 many
207 many
208 text '3'
209 ";
210
211 crate::testing::with_template(tpl, |tree, attributes| {
212 let mut changed = false;
213 let mut children = Children::new(tree, attributes, &mut changed);
214 let mut cntr = 0;
215 children.elements().by_tag("text").each(|el, _| {
216 assert_eq!(el.ident, "text");
217 cntr += 1;
218 });
219
220 assert_eq!(cntr, 3);
221 });
222 }
223
224 #[test]
225 fn filter_by_tag_and_attribute() {
226 let tpl = "
227 many
228 many
229 text [a: 1] '1'
230 text '2'
231 many
232 many
233 text [a: 1] '3'
234 ";
235
236 crate::testing::with_template(tpl, |tree, attributes| {
237 let mut changed = false;
238 let mut children = Children::new(tree, attributes, &mut changed);
239 let mut cntr = 0;
240
241 children.elements().by_tag("text").by_attribute("a", 1).each(|el, _| {
242 assert_eq!(el.ident, "text");
243 cntr += 1;
244 });
245
246 assert_eq!(cntr, 2);
247 });
248 }
249}