1pub mod focusable;
3pub mod scrollable;
4pub mod text_input;
5
6pub use focusable::Focusable;
7pub use scrollable::Scrollable;
8pub use text_input::TextInput;
9
10use crate::widget::Id;
11use crate::{Rectangle, Vector};
12
13use std::any::Any;
14use std::fmt;
15use std::marker::PhantomData;
16use std::sync::Arc;
17
18pub trait Operation<T = ()>: Send {
21 fn container(
26 &mut self,
27 id: Option<&Id>,
28 bounds: Rectangle,
29 operate_on_children: &mut dyn FnMut(&mut dyn Operation<T>),
30 );
31
32 fn focusable(
34 &mut self,
35 _id: Option<&Id>,
36 _bounds: Rectangle,
37 _state: &mut dyn Focusable,
38 ) {
39 }
40
41 fn scrollable(
43 &mut self,
44 _id: Option<&Id>,
45 _bounds: Rectangle,
46 _content_bounds: Rectangle,
47 _translation: Vector,
48 _state: &mut dyn Scrollable,
49 ) {
50 }
51
52 fn text_input(
54 &mut self,
55 _id: Option<&Id>,
56 _bounds: Rectangle,
57 _state: &mut dyn TextInput,
58 ) {
59 }
60
61 fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {}
63
64 fn custom(
66 &mut self,
67 _id: Option<&Id>,
68 _bounds: Rectangle,
69 _state: &mut dyn Any,
70 ) {
71 }
72
73 fn finish(&self) -> Outcome<T> {
75 Outcome::None
76 }
77}
78
79impl<T, O> Operation<O> for Box<T>
80where
81 T: Operation<O> + ?Sized,
82{
83 fn container(
84 &mut self,
85 id: Option<&Id>,
86 bounds: Rectangle,
87 operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
88 ) {
89 self.as_mut().container(id, bounds, operate_on_children);
90 }
91
92 fn focusable(
93 &mut self,
94 id: Option<&Id>,
95 bounds: Rectangle,
96 state: &mut dyn Focusable,
97 ) {
98 self.as_mut().focusable(id, bounds, state);
99 }
100
101 fn scrollable(
102 &mut self,
103 id: Option<&Id>,
104 bounds: Rectangle,
105 content_bounds: Rectangle,
106 translation: Vector,
107 state: &mut dyn Scrollable,
108 ) {
109 self.as_mut().scrollable(
110 id,
111 bounds,
112 content_bounds,
113 translation,
114 state,
115 );
116 }
117
118 fn text_input(
119 &mut self,
120 id: Option<&Id>,
121 bounds: Rectangle,
122 state: &mut dyn TextInput,
123 ) {
124 self.as_mut().text_input(id, bounds, state);
125 }
126
127 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
128 self.as_mut().text(id, bounds, text);
129 }
130
131 fn custom(
132 &mut self,
133 id: Option<&Id>,
134 bounds: Rectangle,
135 state: &mut dyn Any,
136 ) {
137 self.as_mut().custom(id, bounds, state);
138 }
139
140 fn finish(&self) -> Outcome<O> {
141 self.as_ref().finish()
142 }
143}
144
145pub enum Outcome<T> {
147 None,
149
150 Some(T),
152
153 Chain(Box<dyn Operation<T>>),
155}
156
157impl<T> fmt::Debug for Outcome<T>
158where
159 T: fmt::Debug,
160{
161 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
162 match self {
163 Self::None => write!(f, "Outcome::None"),
164 Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
165 Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
166 }
167 }
168}
169
170pub fn black_box<'a, T, O>(
172 operation: &'a mut dyn Operation<T>,
173) -> impl Operation<O> + 'a
174where
175 T: 'a,
176{
177 struct BlackBox<'a, T> {
178 operation: &'a mut dyn Operation<T>,
179 }
180
181 impl<T, O> Operation<O> for BlackBox<'_, T> {
182 fn container(
183 &mut self,
184 id: Option<&Id>,
185 bounds: Rectangle,
186 operate_on_children: &mut dyn FnMut(&mut dyn Operation<O>),
187 ) {
188 self.operation.container(id, bounds, &mut |operation| {
189 operate_on_children(&mut BlackBox { operation });
190 });
191 }
192
193 fn focusable(
194 &mut self,
195 id: Option<&Id>,
196 bounds: Rectangle,
197 state: &mut dyn Focusable,
198 ) {
199 self.operation.focusable(id, bounds, state);
200 }
201
202 fn scrollable(
203 &mut self,
204 id: Option<&Id>,
205 bounds: Rectangle,
206 content_bounds: Rectangle,
207 translation: Vector,
208 state: &mut dyn Scrollable,
209 ) {
210 self.operation.scrollable(
211 id,
212 bounds,
213 content_bounds,
214 translation,
215 state,
216 );
217 }
218
219 fn text_input(
220 &mut self,
221 id: Option<&Id>,
222 bounds: Rectangle,
223 state: &mut dyn TextInput,
224 ) {
225 self.operation.text_input(id, bounds, state);
226 }
227
228 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
229 self.operation.text(id, bounds, text);
230 }
231
232 fn custom(
233 &mut self,
234 id: Option<&Id>,
235 bounds: Rectangle,
236 state: &mut dyn Any,
237 ) {
238 self.operation.custom(id, bounds, state);
239 }
240
241 fn finish(&self) -> Outcome<O> {
242 Outcome::None
243 }
244 }
245
246 BlackBox { operation }
247}
248
249pub fn map<A, B>(
251 operation: impl Operation<A>,
252 f: impl Fn(A) -> B + Send + Sync + 'static,
253) -> impl Operation<B>
254where
255 A: 'static,
256 B: 'static,
257{
258 #[allow(missing_debug_implementations)]
259 struct Map<O, A, B> {
260 operation: O,
261 f: Arc<dyn Fn(A) -> B + Send + Sync>,
262 }
263
264 impl<O, A, B> Operation<B> for Map<O, A, B>
265 where
266 O: Operation<A>,
267 A: 'static,
268 B: 'static,
269 {
270 fn container(
271 &mut self,
272 id: Option<&Id>,
273 bounds: Rectangle,
274 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
275 ) {
276 struct MapRef<'a, A> {
277 operation: &'a mut dyn Operation<A>,
278 }
279
280 impl<A, B> Operation<B> for MapRef<'_, A> {
281 fn container(
282 &mut self,
283 id: Option<&Id>,
284 bounds: Rectangle,
285 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
286 ) {
287 let Self { operation, .. } = self;
288
289 operation.container(id, bounds, &mut |operation| {
290 operate_on_children(&mut MapRef { operation });
291 });
292 }
293
294 fn scrollable(
295 &mut self,
296 id: Option<&Id>,
297 bounds: Rectangle,
298 content_bounds: Rectangle,
299 translation: Vector,
300 state: &mut dyn Scrollable,
301 ) {
302 self.operation.scrollable(
303 id,
304 bounds,
305 content_bounds,
306 translation,
307 state,
308 );
309 }
310
311 fn focusable(
312 &mut self,
313 id: Option<&Id>,
314 bounds: Rectangle,
315 state: &mut dyn Focusable,
316 ) {
317 self.operation.focusable(id, bounds, state);
318 }
319
320 fn text_input(
321 &mut self,
322 id: Option<&Id>,
323 bounds: Rectangle,
324 state: &mut dyn TextInput,
325 ) {
326 self.operation.text_input(id, bounds, state);
327 }
328
329 fn text(
330 &mut self,
331 id: Option<&Id>,
332 bounds: Rectangle,
333 text: &str,
334 ) {
335 self.operation.text(id, bounds, text);
336 }
337
338 fn custom(
339 &mut self,
340 id: Option<&Id>,
341 bounds: Rectangle,
342 state: &mut dyn Any,
343 ) {
344 self.operation.custom(id, bounds, state);
345 }
346 }
347
348 let Self { operation, .. } = self;
349
350 MapRef { operation }.container(id, bounds, operate_on_children);
351 }
352
353 fn focusable(
354 &mut self,
355 id: Option<&Id>,
356 bounds: Rectangle,
357 state: &mut dyn Focusable,
358 ) {
359 self.operation.focusable(id, bounds, state);
360 }
361
362 fn scrollable(
363 &mut self,
364 id: Option<&Id>,
365 bounds: Rectangle,
366 content_bounds: Rectangle,
367 translation: Vector,
368 state: &mut dyn Scrollable,
369 ) {
370 self.operation.scrollable(
371 id,
372 bounds,
373 content_bounds,
374 translation,
375 state,
376 );
377 }
378
379 fn text_input(
380 &mut self,
381 id: Option<&Id>,
382 bounds: Rectangle,
383 state: &mut dyn TextInput,
384 ) {
385 self.operation.text_input(id, bounds, state);
386 }
387
388 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
389 self.operation.text(id, bounds, text);
390 }
391
392 fn custom(
393 &mut self,
394 id: Option<&Id>,
395 bounds: Rectangle,
396 state: &mut dyn Any,
397 ) {
398 self.operation.custom(id, bounds, state);
399 }
400
401 fn finish(&self) -> Outcome<B> {
402 match self.operation.finish() {
403 Outcome::None => Outcome::None,
404 Outcome::Some(output) => Outcome::Some((self.f)(output)),
405 Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
406 operation: next,
407 f: self.f.clone(),
408 })),
409 }
410 }
411 }
412
413 Map {
414 operation,
415 f: Arc::new(f),
416 }
417}
418
419pub fn then<A, B, O>(
422 operation: impl Operation<A> + 'static,
423 f: fn(A) -> O,
424) -> impl Operation<B>
425where
426 A: 'static,
427 B: Send + 'static,
428 O: Operation<B> + 'static,
429{
430 struct Chain<T, O, A, B>
431 where
432 T: Operation<A>,
433 O: Operation<B>,
434 {
435 operation: T,
436 next: fn(A) -> O,
437 _result: PhantomData<B>,
438 }
439
440 impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>
441 where
442 T: Operation<A> + 'static,
443 O: Operation<B> + 'static,
444 A: 'static,
445 B: Send + 'static,
446 {
447 fn container(
448 &mut self,
449 id: Option<&Id>,
450 bounds: Rectangle,
451 operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>),
452 ) {
453 self.operation.container(id, bounds, &mut |operation| {
454 operate_on_children(&mut black_box(operation));
455 });
456 }
457
458 fn focusable(
459 &mut self,
460 id: Option<&Id>,
461 bounds: Rectangle,
462 state: &mut dyn Focusable,
463 ) {
464 self.operation.focusable(id, bounds, state);
465 }
466
467 fn scrollable(
468 &mut self,
469 id: Option<&Id>,
470 bounds: Rectangle,
471 content_bounds: Rectangle,
472 translation: crate::Vector,
473 state: &mut dyn Scrollable,
474 ) {
475 self.operation.scrollable(
476 id,
477 bounds,
478 content_bounds,
479 translation,
480 state,
481 );
482 }
483
484 fn text_input(
485 &mut self,
486 id: Option<&Id>,
487 bounds: Rectangle,
488 state: &mut dyn TextInput,
489 ) {
490 self.operation.text_input(id, bounds, state);
491 }
492
493 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
494 self.operation.text(id, bounds, text);
495 }
496
497 fn custom(
498 &mut self,
499 id: Option<&Id>,
500 bounds: Rectangle,
501 state: &mut dyn Any,
502 ) {
503 self.operation.custom(id, bounds, state);
504 }
505
506 fn finish(&self) -> Outcome<B> {
507 match self.operation.finish() {
508 Outcome::None => Outcome::None,
509 Outcome::Some(value) => {
510 Outcome::Chain(Box::new((self.next)(value)))
511 }
512 Outcome::Chain(operation) => {
513 Outcome::Chain(Box::new(then(operation, self.next)))
514 }
515 }
516 }
517 }
518
519 Chain {
520 operation,
521 next: f,
522 _result: PhantomData,
523 }
524}
525
526pub fn scope<T: 'static>(
529 target: Id,
530 operation: impl Operation<T> + 'static,
531) -> impl Operation<T> {
532 struct ScopedOperation<Message> {
533 target: Id,
534 operation: Box<dyn Operation<Message>>,
535 }
536
537 impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
538 fn container(
539 &mut self,
540 id: Option<&Id>,
541 _bounds: Rectangle,
542 operate_on_children: &mut dyn FnMut(&mut dyn Operation<Message>),
543 ) {
544 if id == Some(&self.target) {
545 operate_on_children(self.operation.as_mut());
546 } else {
547 operate_on_children(self);
548 }
549 }
550
551 fn finish(&self) -> Outcome<Message> {
552 match self.operation.finish() {
553 Outcome::Chain(next) => {
554 Outcome::Chain(Box::new(ScopedOperation {
555 target: self.target.clone(),
556 operation: next,
557 }))
558 }
559 outcome => outcome,
560 }
561 }
562 }
563
564 ScopedOperation {
565 target,
566 operation: Box::new(operation),
567 }
568}