anathema_widgets/components/
deferred.rs1use std::any::Any;
2use std::borrow::Cow;
3
4use anathema_value_resolver::{Attributes, ValueKind};
5
6use crate::nodes::component::Component;
7
8pub struct DeferredComponents {
9 queue: Vec<Command>,
10}
11
12impl DeferredComponents {
13 pub fn new() -> Self {
14 Self { queue: vec![] }
15 }
16
17 pub fn drain(&mut self) -> impl Iterator<Item = Command> + '_ {
18 self.queue.drain(..).rev()
19 }
20
21 pub fn by_name(&mut self, name: impl Into<Cow<'static, str>>) -> QueryBuilder<'_> {
22 QueryBuilder::new(&mut self.queue, Filter::Name(name.into()))
23 }
24
25 pub fn by_attribute(
26 &mut self,
27 key: impl Into<Cow<'static, str>>,
28 value: impl Into<ValueKind<'static>>,
29 ) -> QueryBuilder<'_> {
30 QueryBuilder::new(
31 &mut self.queue,
32 Filter::Attribute {
33 key: key.into(),
34 value: value.into(),
35 },
36 )
37 }
38
39 pub fn nth(&mut self, count: usize) -> QueryBuilder<'_> {
40 QueryBuilder::new(&mut self.queue, Filter::Nth(count))
41 }
42}
43
44pub struct QueryBuilder<'a> {
45 queue: &'a mut Vec<Command>,
46 filter: Filter,
47}
48
49impl<'a> QueryBuilder<'a> {
50 fn new(queue: &'a mut Vec<Command>, filter: Filter) -> Self {
51 Self { queue, filter }
52 }
53
54 pub fn by_name(self, name: impl Into<Cow<'static, str>>) -> Self {
55 Self {
56 queue: self.queue,
57 filter: self.filter.chain(Filter::Name(name.into())),
58 }
59 }
60
61 pub fn by_attribute(self, key: impl Into<Cow<'static, str>>, value: impl Into<ValueKind<'static>>) -> Self {
62 Self {
63 queue: self.queue,
64 filter: self.filter.chain(Filter::Attribute {
65 key: key.into(),
66 value: value.into(),
67 }),
68 }
69 }
70
71 pub fn nth(self, count: usize) -> Self {
72 Self {
73 queue: self.queue,
74 filter: self.filter.chain(Filter::Nth(count)),
75 }
76 }
77
78 pub fn send(self, message: impl Any + Send + Sync) {
79 let command = Command {
80 kind: CommandKind::SendMessage(Box::new(message)),
81 filter: self.filter,
82 };
83 self.queue.push(command);
84 }
85
86 pub fn focus(self) {
87 let command = Command {
88 kind: CommandKind::Focus,
89 filter: self.filter,
90 };
91 self.queue.push(command);
92 }
93}
94
95enum Filter {
96 Name(Cow<'static, str>),
97 Attribute {
98 key: Cow<'static, str>,
99 value: ValueKind<'static>,
100 },
101 Nth(usize),
102 Chain(Box<Self>, Box<Self>),
103}
104
105impl Filter {
106 fn chain(self, other: Self) -> Self {
107 Self::Chain(Box::new(self), Box::new(other))
108 }
109
110 fn filter(&mut self, component: &Component<'_>, attributes: &Attributes<'_>) -> bool {
113 match self {
114 Filter::Name(cow) => component.name == cow,
115 Filter::Attribute { key, value: rhs } => match attributes.get(key) {
116 Some(lhs) => match (lhs, rhs) {
117 (ValueKind::Int(lhs), ValueKind::Int(rhs)) => lhs == rhs,
118 (ValueKind::Float(lhs), ValueKind::Float(rhs)) => lhs == rhs,
119 (ValueKind::Bool(lhs), ValueKind::Bool(rhs)) => lhs == rhs,
120 (ValueKind::Char(lhs), ValueKind::Char(rhs)) => lhs == rhs,
121 (ValueKind::Hex(lhs), ValueKind::Hex(rhs)) => lhs == rhs,
122 (ValueKind::Str(lhs), ValueKind::Str(rhs)) => lhs == rhs,
123 (ValueKind::Null, ValueKind::Null) => true,
124 _ => false,
125 },
126 None => false,
127 },
128 Filter::Nth(0) => true,
129 Filter::Nth(nth) => {
130 *nth -= 1;
131 false
132 }
133 Filter::Chain(first, second) => match first.filter(component, attributes) {
134 true => second.filter(component, attributes),
135 false => false,
136 },
137 }
138 }
139}
140
141pub struct Command {
142 filter: Filter,
143 pub kind: CommandKind,
144}
145
146impl Command {
147 pub fn filter_component(&mut self, component: &Component<'_>, attributes: &Attributes<'_>) -> bool {
148 self.filter.filter(component, attributes)
149 }
150}
151
152pub enum CommandKind {
153 SendMessage(Box<dyn Any + Send + Sync>),
154 Focus,
155}