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