use anathema_state::{Color, Hex};
use anathema_value_resolver::{AttributeStorage, ValueKind};
pub use self::components::Components;
pub use self::elements::Elements;
use crate::WidgetTreeView;
mod components;
mod elements;
pub struct Children<'tree, 'bp>(Nodes<'tree, 'bp>);
impl<'tree, 'bp> Children<'tree, 'bp> {
pub fn new(
children: WidgetTreeView<'tree, 'bp>,
attribute_storage: &'tree mut AttributeStorage<'bp>,
needs_layout: &'tree mut bool,
) -> Self {
Self(Nodes::new(children, attribute_storage, needs_layout))
}
pub fn elements(&mut self) -> Elements<'_, 'tree, 'bp> {
Elements { elements: &mut self.0 }
}
pub fn components(&mut self) -> Components<'_, 'tree, 'bp> {
Components { elements: &mut self.0 }
}
pub fn parent_path(&self) -> &[u16] {
self.0.children.offset
}
}
#[derive(Debug, Copy, Clone)]
pub enum QueryValue<'a> {
Str(&'a str),
Int(i64),
Float(f64),
Bool(bool),
Char(char),
Hex(Hex),
Color(Color),
}
impl<'a> From<&'a str> for QueryValue<'a> {
fn from(value: &'a str) -> Self {
Self::Str(value)
}
}
impl<'a> From<bool> for QueryValue<'a> {
fn from(value: bool) -> Self {
Self::Bool(value)
}
}
macro_rules! impl_from_int {
($t:ty) => {
impl<'a> From<$t> for QueryValue<'a> {
fn from(value: $t) -> Self {
Self::Int(value as i64)
}
}
};
}
impl_from_int!(u8);
impl_from_int!(u16);
impl_from_int!(u32);
impl_from_int!(u64);
impl_from_int!(usize);
impl_from_int!(i8);
impl_from_int!(i16);
impl_from_int!(i32);
impl_from_int!(i64);
impl_from_int!(isize);
impl PartialEq<ValueKind<'_>> for QueryValue<'_> {
fn eq(&self, other: &ValueKind<'_>) -> bool {
match self {
QueryValue::Str(lhs) => match other {
ValueKind::Str(rhs) => lhs == rhs,
_ => false,
},
QueryValue::Bool(lhs) => match other {
ValueKind::Bool(rhs) => lhs == rhs,
_ => false,
},
&QueryValue::Int(lhs) => match other {
&ValueKind::Int(rhs) => lhs == rhs,
_ => false,
},
&QueryValue::Float(lhs) => match other {
&ValueKind::Float(rhs) => lhs == rhs,
_ => false,
},
&QueryValue::Char(lhs) => match other {
&ValueKind::Char(rhs) => lhs == rhs,
_ => false,
},
&QueryValue::Hex(lhs) => match other {
&ValueKind::Hex(rhs) => lhs == rhs,
_ => false,
},
&QueryValue::Color(lhs) => match other {
&ValueKind::Color(rhs) => lhs == rhs,
_ => false,
},
}
}
}
pub struct Nodes<'tree, 'bp> {
children: WidgetTreeView<'tree, 'bp>,
attributes: &'tree mut AttributeStorage<'bp>,
needs_layout: &'tree mut bool,
}
impl<'tree, 'bp> Nodes<'tree, 'bp> {
pub fn new(
children: WidgetTreeView<'tree, 'bp>,
attribute_storage: &'tree mut AttributeStorage<'bp>,
needs_layout: &'tree mut bool,
) -> Self {
Self {
children,
attributes: attribute_storage,
needs_layout,
}
}
}
pub struct Query<'el, 'tree, 'bp, F, T>
where
F: Filter<'bp, Kind = T>,
{
filter: F,
elements: &'el mut Nodes<'tree, 'bp>,
}
impl<'el, 'tree, 'bp, F, T> Filter<'bp> for Query<'el, 'tree, 'bp, F, T>
where
F: Filter<'bp, Kind = T>,
{
type Kind = T;
fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool {
self.filter.filter(arg, attributes)
}
}
pub trait Filter<'bp> {
type Kind;
fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool;
}
#[derive(Debug, Copy, Clone)]
pub struct Chain<A, B> {
a: A,
b: B,
}
impl<A, B> Chain<A, B> {
pub fn new(a: A, b: B) -> Self {
Self { a, b }
}
}
impl<'bp, A, B> Filter<'bp> for Chain<A, B>
where
A: Filter<'bp>,
B: Filter<'bp, Kind = A::Kind>,
{
type Kind = A::Kind;
fn filter(&self, arg: &Self::Kind, attributes: &mut AttributeStorage<'bp>) -> bool {
self.a.filter(arg, attributes) && self.b.filter(arg, attributes)
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn filter_by_tag() {
let tpl = "
many
many
text '1'
text '2'
many
many
text '3'
";
crate::testing::with_template(tpl, |tree, attributes| {
let mut changed = false;
let mut children = Children::new(tree, attributes, &mut changed);
let mut cntr = 0;
children.elements().by_tag("text").each(|el, _| {
assert_eq!(el.ident, "text");
cntr += 1;
});
assert_eq!(cntr, 3);
});
}
#[test]
fn filter_by_tag_and_attribute() {
let tpl = "
many
many
text [a: 1] '1'
text '2'
many
many
text [a: 1] '3'
";
crate::testing::with_template(tpl, |tree, attributes| {
let mut changed = false;
let mut children = Children::new(tree, attributes, &mut changed);
let mut cntr = 0;
children.elements().by_tag("text").by_attribute("a", 1).each(|el, _| {
assert_eq!(el.ident, "text");
cntr += 1;
});
assert_eq!(cntr, 2);
});
}
}