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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<T>));
28
29 fn container(&mut self, _id: Option<&Id>, _bounds: Rectangle) {}
31
32 fn scrollable(
34 &mut self,
35 _id: Option<&Id>,
36 _bounds: Rectangle,
37 _content_bounds: Rectangle,
38 _translation: Vector,
39 _state: &mut dyn Scrollable,
40 ) {
41 }
42
43 fn focusable(
45 &mut self,
46 _id: Option<&Id>,
47 _bounds: Rectangle,
48 _state: &mut dyn Focusable,
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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>)) {
84 self.as_mut().traverse(operate);
85 }
86
87 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
88 self.as_mut().container(id, bounds);
89 }
90
91 fn focusable(
92 &mut self,
93 id: Option<&Id>,
94 bounds: Rectangle,
95 state: &mut dyn Focusable,
96 ) {
97 self.as_mut().focusable(id, bounds, state);
98 }
99
100 fn scrollable(
101 &mut self,
102 id: Option<&Id>,
103 bounds: Rectangle,
104 content_bounds: Rectangle,
105 translation: Vector,
106 state: &mut dyn Scrollable,
107 ) {
108 self.as_mut().scrollable(
109 id,
110 bounds,
111 content_bounds,
112 translation,
113 state,
114 );
115 }
116
117 fn text_input(
118 &mut self,
119 id: Option<&Id>,
120 bounds: Rectangle,
121 state: &mut dyn TextInput,
122 ) {
123 self.as_mut().text_input(id, bounds, state);
124 }
125
126 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
127 self.as_mut().text(id, bounds, text);
128 }
129
130 fn custom(
131 &mut self,
132 id: Option<&Id>,
133 bounds: Rectangle,
134 state: &mut dyn Any,
135 ) {
136 self.as_mut().custom(id, bounds, state);
137 }
138
139 fn finish(&self) -> Outcome<O> {
140 self.as_ref().finish()
141 }
142}
143
144pub enum Outcome<T> {
146 None,
148
149 Some(T),
151
152 Chain(Box<dyn Operation<T>>),
154}
155
156impl<T> fmt::Debug for Outcome<T>
157where
158 T: fmt::Debug,
159{
160 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
161 match self {
162 Self::None => write!(f, "Outcome::None"),
163 Self::Some(output) => write!(f, "Outcome::Some({output:?})"),
164 Self::Chain(_) => write!(f, "Outcome::Chain(...)"),
165 }
166 }
167}
168
169pub fn black_box<'a, T, O>(
171 operation: &'a mut dyn Operation<T>,
172) -> impl Operation<O> + 'a
173where
174 T: 'a,
175{
176 struct BlackBox<'a, T> {
177 operation: &'a mut dyn Operation<T>,
178 }
179
180 impl<T, O> Operation<O> for BlackBox<'_, T> {
181 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>))
182 where
183 Self: Sized,
184 {
185 self.operation.traverse(&mut |operation| {
186 operate(&mut BlackBox { operation });
187 });
188 }
189
190 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
191 self.operation.container(id, bounds);
192 }
193
194 fn focusable(
195 &mut self,
196 id: Option<&Id>,
197 bounds: Rectangle,
198 state: &mut dyn Focusable,
199 ) {
200 self.operation.focusable(id, bounds, state);
201 }
202
203 fn scrollable(
204 &mut self,
205 id: Option<&Id>,
206 bounds: Rectangle,
207 content_bounds: Rectangle,
208 translation: Vector,
209 state: &mut dyn Scrollable,
210 ) {
211 self.operation.scrollable(
212 id,
213 bounds,
214 content_bounds,
215 translation,
216 state,
217 );
218 }
219
220 fn text_input(
221 &mut self,
222 id: Option<&Id>,
223 bounds: Rectangle,
224 state: &mut dyn TextInput,
225 ) {
226 self.operation.text_input(id, bounds, state);
227 }
228
229 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
230 self.operation.text(id, bounds, text);
231 }
232
233 fn custom(
234 &mut self,
235 id: Option<&Id>,
236 bounds: Rectangle,
237 state: &mut dyn Any,
238 ) {
239 self.operation.custom(id, bounds, state);
240 }
241
242 fn finish(&self) -> Outcome<O> {
243 Outcome::None
244 }
245 }
246
247 BlackBox { operation }
248}
249
250pub fn map<A, B>(
252 operation: impl Operation<A>,
253 f: impl Fn(A) -> B + Send + Sync + 'static,
254) -> impl Operation<B>
255where
256 A: 'static,
257 B: 'static,
258{
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 traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
271 struct MapRef<'a, A> {
272 operation: &'a mut dyn Operation<A>,
273 }
274
275 impl<A, B> Operation<B> for MapRef<'_, A> {
276 fn traverse(
277 &mut self,
278 operate: &mut dyn FnMut(&mut dyn Operation<B>),
279 ) {
280 self.operation.traverse(&mut |operation| {
281 operate(&mut MapRef { operation });
282 });
283 }
284
285 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
286 let Self { operation, .. } = self;
287
288 operation.container(id, bounds);
289 }
290
291 fn scrollable(
292 &mut self,
293 id: Option<&Id>,
294 bounds: Rectangle,
295 content_bounds: Rectangle,
296 translation: Vector,
297 state: &mut dyn Scrollable,
298 ) {
299 self.operation.scrollable(
300 id,
301 bounds,
302 content_bounds,
303 translation,
304 state,
305 );
306 }
307
308 fn focusable(
309 &mut self,
310 id: Option<&Id>,
311 bounds: Rectangle,
312 state: &mut dyn Focusable,
313 ) {
314 self.operation.focusable(id, bounds, state);
315 }
316
317 fn text_input(
318 &mut self,
319 id: Option<&Id>,
320 bounds: Rectangle,
321 state: &mut dyn TextInput,
322 ) {
323 self.operation.text_input(id, bounds, state);
324 }
325
326 fn text(
327 &mut self,
328 id: Option<&Id>,
329 bounds: Rectangle,
330 text: &str,
331 ) {
332 self.operation.text(id, bounds, text);
333 }
334
335 fn custom(
336 &mut self,
337 id: Option<&Id>,
338 bounds: Rectangle,
339 state: &mut dyn Any,
340 ) {
341 self.operation.custom(id, bounds, state);
342 }
343 }
344
345 self.operation.traverse(&mut |operation| {
346 operate(&mut MapRef { operation });
347 });
348 }
349
350 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
351 self.operation.container(id, bounds);
352 }
353
354 fn focusable(
355 &mut self,
356 id: Option<&Id>,
357 bounds: Rectangle,
358 state: &mut dyn Focusable,
359 ) {
360 self.operation.focusable(id, bounds, state);
361 }
362
363 fn scrollable(
364 &mut self,
365 id: Option<&Id>,
366 bounds: Rectangle,
367 content_bounds: Rectangle,
368 translation: Vector,
369 state: &mut dyn Scrollable,
370 ) {
371 self.operation.scrollable(
372 id,
373 bounds,
374 content_bounds,
375 translation,
376 state,
377 );
378 }
379
380 fn text_input(
381 &mut self,
382 id: Option<&Id>,
383 bounds: Rectangle,
384 state: &mut dyn TextInput,
385 ) {
386 self.operation.text_input(id, bounds, state);
387 }
388
389 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
390 self.operation.text(id, bounds, text);
391 }
392
393 fn custom(
394 &mut self,
395 id: Option<&Id>,
396 bounds: Rectangle,
397 state: &mut dyn Any,
398 ) {
399 self.operation.custom(id, bounds, state);
400 }
401
402 fn finish(&self) -> Outcome<B> {
403 match self.operation.finish() {
404 Outcome::None => Outcome::None,
405 Outcome::Some(output) => Outcome::Some((self.f)(output)),
406 Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
407 operation: next,
408 f: self.f.clone(),
409 })),
410 }
411 }
412 }
413
414 Map {
415 operation,
416 f: Arc::new(f),
417 }
418}
419
420pub fn then<A, B, O>(
423 operation: impl Operation<A> + 'static,
424 f: fn(A) -> O,
425) -> impl Operation<B>
426where
427 A: 'static,
428 B: Send + 'static,
429 O: Operation<B> + 'static,
430{
431 struct Chain<T, O, A, B>
432 where
433 T: Operation<A>,
434 O: Operation<B>,
435 {
436 operation: T,
437 next: fn(A) -> O,
438 _result: PhantomData<B>,
439 }
440
441 impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>
442 where
443 T: Operation<A> + 'static,
444 O: Operation<B> + 'static,
445 A: 'static,
446 B: Send + 'static,
447 {
448 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
449 self.operation.traverse(&mut |operation| {
450 operate(&mut black_box(operation));
451 });
452 }
453
454 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
455 self.operation.container(id, bounds);
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 current: Option<Id>,
535 operation: Box<dyn Operation<Message>>,
536 }
537
538 impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
539 fn traverse(
540 &mut self,
541 operate: &mut dyn FnMut(&mut dyn Operation<Message>),
542 ) {
543 if self.current.as_ref() == Some(&self.target) {
544 self.operation.as_mut().traverse(operate);
545 } else {
546 operate(self);
547 }
548
549 self.current = None;
550 }
551
552 fn container(&mut self, id: Option<&Id>, _bounds: Rectangle) {
553 self.current = id.cloned();
554 }
555
556 fn finish(&self) -> Outcome<Message> {
557 match self.operation.finish() {
558 Outcome::Chain(next) => {
559 Outcome::Chain(Box::new(ScopedOperation {
560 target: self.target.clone(),
561 current: None,
562 operation: next,
563 }))
564 }
565 outcome => outcome,
566 }
567 }
568 }
569
570 ScopedOperation {
571 target,
572 current: None,
573 operation: Box::new(operation),
574 }
575}