diff options
Diffstat (limited to 'core/src/widget')
| -rw-r--r-- | core/src/widget/operation.rs | 116 | 
1 files changed, 115 insertions, 1 deletions
| diff --git a/core/src/widget/operation.rs b/core/src/widget/operation.rs index 53688a21..ad188c36 100644 --- a/core/src/widget/operation.rs +++ b/core/src/widget/operation.rs @@ -11,6 +11,7 @@ use crate::widget::Id;  use std::any::Any;  use std::fmt; +use std::rc::Rc;  /// A piece of logic that can traverse the widget tree of an application in  /// order to query or update some widget state. @@ -68,9 +69,122 @@ where      }  } +/// Maps the output of an [`Operation`] using the given function. +pub fn map<A, B>( +    operation: Box<dyn Operation<A>>, +    f: impl Fn(A) -> B + 'static, +) -> impl Operation<B> +where +    A: 'static, +    B: 'static, +{ +    #[allow(missing_debug_implementations)] +    struct Map<A, B> { +        operation: Box<dyn Operation<A>>, +        f: Rc<dyn Fn(A) -> B>, +    } + +    impl<A, B> Operation<B> for Map<A, B> +    where +        A: 'static, +        B: 'static, +    { +        fn container( +            &mut self, +            id: Option<&Id>, +            operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>), +        ) { +            struct MapRef<'a, A> { +                operation: &'a mut dyn Operation<A>, +            } + +            impl<'a, A, B> Operation<B> for MapRef<'a, A> { +                fn container( +                    &mut self, +                    id: Option<&Id>, +                    operate_on_children: &mut dyn FnMut(&mut dyn Operation<B>), +                ) { +                    let Self { operation, .. } = self; + +                    operation.container(id, &mut |operation| { +                        operate_on_children(&mut MapRef { operation }); +                    }); +                } + +                fn scrollable( +                    &mut self, +                    state: &mut dyn Scrollable, +                    id: Option<&Id>, +                ) { +                    self.operation.scrollable(state, id); +                } + +                fn focusable( +                    &mut self, +                    state: &mut dyn Focusable, +                    id: Option<&Id>, +                ) { +                    self.operation.focusable(state, id); +                } + +                fn text_input( +                    &mut self, +                    state: &mut dyn TextInput, +                    id: Option<&Id>, +                ) { +                    self.operation.text_input(state, id); +                } + +                fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { +                    self.operation.custom(state, id); +                } +            } + +            let Self { operation, .. } = self; + +            MapRef { +                operation: operation.as_mut(), +            } +            .container(id, operate_on_children); +        } + +        fn focusable(&mut self, state: &mut dyn Focusable, id: Option<&Id>) { +            self.operation.focusable(state, id); +        } + +        fn scrollable(&mut self, state: &mut dyn Scrollable, id: Option<&Id>) { +            self.operation.scrollable(state, id); +        } + +        fn text_input(&mut self, state: &mut dyn TextInput, id: Option<&Id>) { +            self.operation.text_input(state, id); +        } + +        fn custom(&mut self, state: &mut dyn Any, id: Option<&Id>) { +            self.operation.custom(state, id); +        } + +        fn finish(&self) -> Outcome<B> { +            match self.operation.finish() { +                Outcome::None => Outcome::None, +                Outcome::Some(output) => Outcome::Some((self.f)(output)), +                Outcome::Chain(next) => Outcome::Chain(Box::new(Map { +                    operation: next, +                    f: self.f.clone(), +                })), +            } +        } +    } + +    Map { +        operation, +        f: Rc::new(f), +    } +} +  /// Produces an [`Operation`] that applies the given [`Operation`] to the  /// children of a container with the given [`Id`]. -pub fn scoped<T: 'static>( +pub fn scope<T: 'static>(      target: Id,      operation: impl Operation<T> + 'static,  ) -> impl Operation<T> { | 
