Skip to main content

anathema_widgets/query/
mod.rs

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
114// -----------------------------------------------------------------------------
115//   - Elements -
116// -----------------------------------------------------------------------------
117pub 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
137// -----------------------------------------------------------------------------
138//   - Query -
139// -----------------------------------------------------------------------------
140pub 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
159// -----------------------------------------------------------------------------
160//   - Filter -
161// -----------------------------------------------------------------------------
162pub trait Filter<'bp> {
163    type Kind;
164
165    fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool;
166}
167
168// -----------------------------------------------------------------------------
169//   - Chain -
170// -----------------------------------------------------------------------------
171#[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}