1pub mod focusable;
3pub mod scrollable;
4pub mod search_id;
5pub mod text_input;
6
7pub use focusable::Focusable;
8pub use scrollable::Scrollable;
9pub use text_input::TextInput;
10
11use crate::widget::Id;
12use crate::{Rectangle, Vector};
13
14use std::any::Any;
15use std::fmt;
16use std::marker::PhantomData;
17use std::sync::Arc;
18
19pub trait Operation<T = ()>: Send {
22 fn container(
27 &mut self,
28 id: Option<&Id>,
29 bounds: Rectangle,
30 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
31 );
32
33 fn focusable(&mut self, _state: &mut dyn Focusable, _id: Option<&Id>) {}
35
36 fn scrollable(
38 &mut self,
39 _state: &mut dyn Scrollable,
40 _id: Option<&Id>,
41 _bounds: Rectangle,
42 _content_bounds: Rectangle,
43 _translation: Vector,
44 ) {
45 }
46
47 fn text_input(&mut self, _state: &mut dyn TextInput, _id: Option<&Id>) {}
49
50 fn custom(&mut self, _state: &mut dyn Any, _id: Option<&Id>) {}
52
53 fn finish(&self) -> Outcome<T> {
55 Outcome::None
56 }
57}
58
59impl<T, O> Operation<O> for Box<T>
60where
61 T: Operation<O> + ?Sized,
62{
63 fn container(
64 &mut self,
65 id: Option<&Id>,
66 bounds: Rectangle,
67 operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
68 ) {
69 self.as_mut().container(id, bounds, operate_on_children);
70 }
71
72 fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
73 self.as_mut().focusable(state, id);
74 }
75
76 fn scrollable(
77 &mut self,
78 state: &mut dyn Scrollable,
79 id: Option<&Id>,
80 bounds: Rectangle,
81 content_bounds: Rectangle,
82 translation: Vector,
83 ) {
84 self.as_mut().scrollable(
85 state,
86 id,
87 bounds,
88 content_bounds,
89 translation,
90 );
91 }
92
93 fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
94 self.as_mut().text_input(state, id);
95 }
96
97 fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
98 self.as_mut().custom(state, id);
99 }
100
101 fn finish(&self) -> Outcome<O> {
102 self.as_ref().finish()
103 }
104}
105
106pub enum Outcome<T> {
108 None,
110
111 Some(T),
113
114 Chain(Box<dyn Operation<T>>),
116}
117
118impl<T> fmt::Debug for Outcome<T>
119where
120 T: fmt::Debug,
121{
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 match self {
124 Self::None => write!(f, "Outcome::None"),
125 Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
126 Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
127 }
128 }
129}
130
131pub fn black_box<'a, T, O>(
133 operation: &'a mut dyn Operation<T>,
134) -> impl Operation<O> + 'a
135where
136 T: 'a,
137{
138 struct BlackBox<'a, T> {
139 operation: &'a mut dyn Operation<T>,
140 }
141
142 impl<'a, T, O> Operation<O> for BlackBox<'a, T> {
143 fn container(
144 &mut self,
145 id: Option<&Id>,
146 bounds: Rectangle,
147 operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
148 ) {
149 self.operation.container(id, bounds, &mut |operation| {
150 operate_on_children(&mut BlackBox { operation });
151 });
152 }
153
154 fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
155 self.operation.focusable(state, id);
156 }
157
158 fn scrollable(
159 &mut self,
160 state: &mut dyn Scrollable,
161 id: Option<&Id>,
162 bounds: Rectangle,
163 content_bounds: Rectangle,
164 translation: Vector,
165 ) {
166 self.operation.scrollable(
167 state,
168 id,
169 bounds,
170 content_bounds,
171 translation,
172 );
173 }
174
175 fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
176 self.operation.text_input(state, id);
177 }
178
179 fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
180 self.operation.custom(state, id);
181 }
182
183 fn finish(&self) -> Outcome<O> {
184 Outcome::None
185 }
186 }
187
188 BlackBox { operation }
189}
190
191pub fn map<A, B>(
193 operation: impl Operation<A>,
194 f: impl Fn(A) -> B + Send + Sync + 'static,
195) -> impl Operation<B>
196where
197 A: 'static,
198 B: 'static,
199{
200 #[allow(missing_debug_implementations)]
201 struct Map<O, A, B> {
202 operation: O,
203 f: Arc<dyn Fn(A) -> B + Send + Sync>,
204 }
205
206 impl<O, A, B> Operation<B> for Map<O, A, B>
207 where
208 O: Operation<A>,
209 A: 'static,
210 B: 'static,
211 {
212 fn container(
213 &mut self,
214 id: Option<&Id>,
215 bounds: Rectangle,
216 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
217 ) {
218 struct MapRef<'a, A> {
219 operation: &'a mut dyn Operation<A>,
220 }
221
222 impl<'a, A, B> Operation<B> for MapRef<'a, A> {
223 fn container(
224 &mut self,
225 id: Option<&Id>,
226 bounds: Rectangle,
227 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
228 ) {
229 let Self { operation, .. } = self;
230
231 operation.container(id, bounds, &mut |operation| {
232 operate_on_children(&mut MapRef { operation });
233 });
234 }
235
236 fn scrollable(
237 &mut self,
238 state: &mut dyn Scrollable,
239 id: Option<&Id>,
240 bounds: Rectangle,
241 content_bounds: Rectangle,
242 translation: Vector,
243 ) {
244 self.operation.scrollable(
245 state,
246 id,
247 bounds,
248 content_bounds,
249 translation,
250 );
251 }
252
253 fn focusable(
254 &mut self,
255 state: &mut dyn Focusable,
256 id: Option<&Id>,
257 ) {
258 self.operation.focusable(state, id);
259 }
260
261 fn text_input(
262 &mut self,
263 state: &mut dyn TextInput,
264 id: Option<&Id>,
265 ) {
266 self.operation.text_input(state, id);
267 }
268
269 fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
270 self.operation.custom(state, id);
271 }
272 }
273
274 let Self { operation, .. } = self;
275
276 MapRef { operation }.container(id, bounds, operate_on_children);
277 }
278
279 fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
280 self.operation.focusable(state, id);
281 }
282
283 fn scrollable(
284 &mut self,
285 state: &mut dyn Scrollable,
286 id: Option<&Id>,
287 bounds: Rectangle,
288 content_bounds: Rectangle,
289 translation: Vector,
290 ) {
291 self.operation.scrollable(
292 state,
293 id,
294 bounds,
295 content_bounds,
296 translation,
297 );
298 }
299
300 fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
301 self.operation.text_input(state, id);
302 }
303
304 fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) {
305 self.operation.custom(state, id);
306 }
307
308 fn finish(&self) -> Outcome<B> {
309 match self.operation.finish() {
310 Outcome::None => Outcome::None,
311 Outcome::Some(output) => Outcome::Some((self.f)(output)),
312 Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
313 operation: next,
314 f: self.f.clone(),
315 })),
316 }
317 }
318 }
319
320 Map {
321 operation,
322 f: Arc::new(f),
323 }
324}
325
326pub fn then<A, B, O>(
329 operation: impl Operation<A> + 'static,
330 f: fn(A) -> O,
331) -> impl Operation<B>
332where
333 A: 'static,
334 B: Send + 'static,
335 O: Operation<B> + 'static,
336{
337 struct Chain<T, O, A, B>
338 where
339 T: Operation<A>,
340 O: Operation<B>,
341 {
342 operation: T,
343 next: fn(A) -> O,
344 _result: PhantomData<B>,
345 }
346
347 impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>
348 where
349 T: Operation<A> + 'static,
350 O: Operation<B> + 'static,
351 A: 'static,
352 B: Send + 'static,
353 {
354 fn container(
355 &mut self,
356 id: Option<&Id>,
357 bounds: Rectangle,
358 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
359 ) {
360 self.operation.container(id, bounds, &mut |operation| {
361 operate_on_children(&mut black_box(operation));
362 });
363 }
364
365 fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) {
366 self.operation.focusable(state, id);
367 }
368
369 fn scrollable(
370 &mut self,
371 state: &mut dyn Scrollable,
372 id: Option<&Id>,
373 bounds: Rectangle,
374 content_bounds: Rectangle,
375 translation: crate::Vector,
376 ) {
377 self.operation.scrollable(
378 state,
379 id,
380 bounds,
381 content_bounds,
382 translation,
383 );
384 }
385
386 fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) {
387 self.operation.text_input(state, id);
388 }
389
390 fn custom(&mut self, state: &mut dyn std::any::Any, id: Option<&Id>) {
391 self.operation.custom(state, id);
392 }
393
394 fn finish(&self) -> Outcome<B> {
395 match self.operation.finish() {
396 Outcome::None => Outcome::None,
397 Outcome::Some(value) => {
398 Outcome::Chain(Box::new((self.next)(value)))
399 }
400 Outcome::Chain(operation) => {
401 Outcome::Chain(Box::new(then(operation, self.next)))
402 }
403 }
404 }
405 }
406
407 Chain {
408 operation,
409 next: f,
410 _result: PhantomData,
411 }
412}
413
414pub fn scoped<T: 'static>(
417 target: Id,
418 operation: impl Operation<T> + 'static,
419) -> impl Operation<T> {
420 struct ScopedOperation<Message> {
421 target: Id,
422 operation: Box<dyn Operation<Message>>,
423 }
424
425 impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
426 fn container(
427 &mut self,
428 id: Option<&Id>,
429 _bounds: Rectangle,
430 operate_on_children: &mut dyn FnMut(&mut dyn Operation<Message>),
431 ) {
432 if id == Some(&self.target) {
433 operate_on_children(self.operation.as_mut());
434 } else {
435 operate_on_children(self);
436 }
437 }
438
439 fn finish(&self) -> Outcome<Message> {
440 match self.operation.finish() {
441 Outcome::Chain(next) => {
442 Outcome::Chain(Box::new(ScopedOperation {
443 target: self.target.clone(),
444 operation: next,
445 }))
446 }
447 outcome => outcome,
448 }
449 }
450 }
451
452 ScopedOperation {
453 target,
454 operation: Box::new(operation),
455 }
456}