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(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Focusable) {}
45
46 fn text_input(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn TextInput) {}
48
49 fn text(&mut self, _id: Option<&Id>, _bounds: Rectangle, _text: &str) {}
51
52 fn custom(&mut self, _id: Option<&Id>, _bounds: Rectangle, _state: &mut dyn Any) {}
54
55 fn finish(&self) -> Outcome<T> {
57 Outcome::None
58 }
59}
60
61impl<T, O> Operation<O> for Box<T>
62where
63 T: Operation<O> + ?Sized,
64{
65 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>)) {
66 self.as_mut().traverse(operate);
67 }
68
69 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
70 self.as_mut().container(id, bounds);
71 }
72
73 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
74 self.as_mut().focusable(id, bounds, state);
75 }
76
77 fn scrollable(
78 &mut self,
79 id: Option<&Id>,
80 bounds: Rectangle,
81 content_bounds: Rectangle,
82 translation: Vector,
83 state: &mut dyn Scrollable,
84 ) {
85 self.as_mut()
86 .scrollable(id, bounds, content_bounds, translation, state);
87 }
88
89 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
90 self.as_mut().text_input(id, bounds, state);
91 }
92
93 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
94 self.as_mut().text(id, bounds, text);
95 }
96
97 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
98 self.as_mut().custom(id, bounds, state);
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>(operation: &'a mut dyn Operation<T>) -> impl Operation<O> + 'a
133where
134 T: 'a,
135{
136 struct BlackBox<'a, T> {
137 operation: &'a mut dyn Operation<T>,
138 }
139
140 impl<T, O> Operation<O> for BlackBox<'_, T> {
141 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<O>))
142 where
143 Self: Sized,
144 {
145 self.operation.traverse(&mut |operation| {
146 operate(&mut BlackBox { operation });
147 });
148 }
149
150 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
151 self.operation.container(id, bounds);
152 }
153
154 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
155 self.operation.focusable(id, bounds, state);
156 }
157
158 fn scrollable(
159 &mut self,
160 id: Option<&Id>,
161 bounds: Rectangle,
162 content_bounds: Rectangle,
163 translation: Vector,
164 state: &mut dyn Scrollable,
165 ) {
166 self.operation
167 .scrollable(id, bounds, content_bounds, translation, state);
168 }
169
170 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
171 self.operation.text_input(id, bounds, state);
172 }
173
174 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
175 self.operation.text(id, bounds, text);
176 }
177
178 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
179 self.operation.custom(id, bounds, state);
180 }
181
182 fn finish(&self) -> Outcome<O> {
183 Outcome::None
184 }
185 }
186
187 BlackBox { operation }
188}
189
190pub fn map<A, B>(
192 operation: impl Operation<A>,
193 f: impl Fn(A) -> B + Send + Sync + 'static,
194) -> impl Operation<B>
195where
196 A: 'static,
197 B: 'static,
198{
199 struct Map<O, A, B> {
200 operation: O,
201 f: Arc<dyn Fn(A) -> B + Send + Sync>,
202 }
203
204 impl<O, A, B> Operation<B> for Map<O, A, B>
205 where
206 O: Operation<A>,
207 A: 'static,
208 B: 'static,
209 {
210 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
211 struct MapRef<'a, A> {
212 operation: &'a mut dyn Operation<A>,
213 }
214
215 impl<A, B> Operation<B> for MapRef<'_, A> {
216 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
217 self.operation.traverse(&mut |operation| {
218 operate(&mut MapRef { operation });
219 });
220 }
221
222 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
223 let Self { operation, .. } = self;
224
225 operation.container(id, bounds);
226 }
227
228 fn scrollable(
229 &mut self,
230 id: Option<&Id>,
231 bounds: Rectangle,
232 content_bounds: Rectangle,
233 translation: Vector,
234 state: &mut dyn Scrollable,
235 ) {
236 self.operation
237 .scrollable(id, bounds, content_bounds, translation, state);
238 }
239
240 fn focusable(
241 &mut self,
242 id: Option<&Id>,
243 bounds: Rectangle,
244 state: &mut dyn Focusable,
245 ) {
246 self.operation.focusable(id, bounds, state);
247 }
248
249 fn text_input(
250 &mut self,
251 id: Option<&Id>,
252 bounds: Rectangle,
253 state: &mut dyn TextInput,
254 ) {
255 self.operation.text_input(id, bounds, state);
256 }
257
258 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
259 self.operation.text(id, bounds, text);
260 }
261
262 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
263 self.operation.custom(id, bounds, state);
264 }
265 }
266
267 self.operation.traverse(&mut |operation| {
268 operate(&mut MapRef { operation });
269 });
270 }
271
272 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
273 self.operation.container(id, bounds);
274 }
275
276 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
277 self.operation.focusable(id, bounds, state);
278 }
279
280 fn scrollable(
281 &mut self,
282 id: Option<&Id>,
283 bounds: Rectangle,
284 content_bounds: Rectangle,
285 translation: Vector,
286 state: &mut dyn Scrollable,
287 ) {
288 self.operation
289 .scrollable(id, bounds, content_bounds, translation, state);
290 }
291
292 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
293 self.operation.text_input(id, bounds, state);
294 }
295
296 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
297 self.operation.text(id, bounds, text);
298 }
299
300 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
301 self.operation.custom(id, bounds, state);
302 }
303
304 fn finish(&self) -> Outcome<B> {
305 match self.operation.finish() {
306 Outcome::None => Outcome::None,
307 Outcome::Some(output) => Outcome::Some((self.f)(output)),
308 Outcome::Chain(next) => Outcome::Chain(Box::new(Map {
309 operation: next,
310 f: self.f.clone(),
311 })),
312 }
313 }
314 }
315
316 Map {
317 operation,
318 f: Arc::new(f),
319 }
320}
321
322pub fn then<A, B, O>(operation: impl Operation<A> + 'static, f: fn(A) -> O) -> impl Operation<B>
325where
326 A: 'static,
327 B: Send + 'static,
328 O: Operation<B> + 'static,
329{
330 struct Chain<T, O, A, B>
331 where
332 T: Operation<A>,
333 O: Operation<B>,
334 {
335 operation: T,
336 next: fn(A) -> O,
337 _result: PhantomData<B>,
338 }
339
340 impl<T, O, A, B> Operation<B> for Chain<T, O, A, B>
341 where
342 T: Operation<A> + 'static,
343 O: Operation<B> + 'static,
344 A: 'static,
345 B: Send + 'static,
346 {
347 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<B>)) {
348 self.operation.traverse(&mut |operation| {
349 operate(&mut black_box(operation));
350 });
351 }
352
353 fn container(&mut self, id: Option<&Id>, bounds: Rectangle) {
354 self.operation.container(id, bounds);
355 }
356
357 fn focusable(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Focusable) {
358 self.operation.focusable(id, bounds, state);
359 }
360
361 fn scrollable(
362 &mut self,
363 id: Option<&Id>,
364 bounds: Rectangle,
365 content_bounds: Rectangle,
366 translation: crate::Vector,
367 state: &mut dyn Scrollable,
368 ) {
369 self.operation
370 .scrollable(id, bounds, content_bounds, translation, state);
371 }
372
373 fn text_input(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn TextInput) {
374 self.operation.text_input(id, bounds, state);
375 }
376
377 fn text(&mut self, id: Option<&Id>, bounds: Rectangle, text: &str) {
378 self.operation.text(id, bounds, text);
379 }
380
381 fn custom(&mut self, id: Option<&Id>, bounds: Rectangle, state: &mut dyn Any) {
382 self.operation.custom(id, bounds, state);
383 }
384
385 fn finish(&self) -> Outcome<B> {
386 match self.operation.finish() {
387 Outcome::None => Outcome::None,
388 Outcome::Some(value) => Outcome::Chain(Box::new((self.next)(value))),
389 Outcome::Chain(operation) => Outcome::Chain(Box::new(then(operation, self.next))),
390 }
391 }
392 }
393
394 Chain {
395 operation,
396 next: f,
397 _result: PhantomData,
398 }
399}
400
401pub fn scope<T: 'static>(target: Id, operation: impl Operation<T> + 'static) -> impl Operation<T> {
404 struct ScopedOperation<Message> {
405 target: Id,
406 current: Option<Id>,
407 operation: Box<dyn Operation<Message>>,
408 }
409
410 impl<Message: 'static> Operation<Message> for ScopedOperation<Message> {
411 fn traverse(&mut self, operate: &mut dyn FnMut(&mut dyn Operation<Message>)) {
412 if self.current.as_ref() == Some(&self.target) {
413 self.operation.as_mut().traverse(operate);
414 } else {
415 operate(self);
416 }
417
418 self.current = None;
419 }
420
421 fn container(&mut self, id: Option<&Id>, _bounds: Rectangle) {
422 self.current = id.cloned();
423 }
424
425 fn finish(&self) -> Outcome<Message> {
426 match self.operation.finish() {
427 Outcome::Chain(next) => Outcome::Chain(Box::new(ScopedOperation {
428 target: self.target.clone(),
429 current: None,
430 operation: next,
431 })),
432 outcome => outcome,
433 }
434 }
435 }
436
437 ScopedOperation {
438 target,
439 current: None,
440 operation: Box::new(operation),
441 }
442}