diff options
Diffstat (limited to '')
| -rw-r--r-- | lazy/src/lib.rs | 3 | ||||
| -rw-r--r-- | lazy/src/pure.rs | 31 | ||||
| -rw-r--r-- | lazy/src/pure/component.rs | 476 | ||||
| -rw-r--r-- | lazy/src/pure/responsive.rs | 381 | 
4 files changed, 891 insertions, 0 deletions
| diff --git a/lazy/src/lib.rs b/lazy/src/lib.rs index 05fce765..5d7d10e4 100644 --- a/lazy/src/lib.rs +++ b/lazy/src/lib.rs @@ -1,6 +1,9 @@  pub mod component;  pub mod responsive; +#[cfg(feature = "pure")] +pub mod pure; +  pub use component::Component;  pub use responsive::Responsive; diff --git a/lazy/src/pure.rs b/lazy/src/pure.rs new file mode 100644 index 00000000..dc500e5e --- /dev/null +++ b/lazy/src/pure.rs @@ -0,0 +1,31 @@ +mod component; +mod responsive; + +pub use component::Component; +pub use responsive::Responsive; + +use iced_native::Size; +use iced_pure::Element; + +/// Turns an implementor of [`Component`] into an [`Element`] that can be +/// embedded in any application. +pub fn component<'a, C, Message, Renderer>( +    component: C, +) -> Element<'a, Message, Renderer> +where +    C: Component<Message, Renderer> + 'a, +    C::State: 'static, +    Message: 'a, +    Renderer: iced_native::Renderer + 'a, +{ +    component::view(component) +} + +pub fn responsive<'a, Message, Renderer>( +    f: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, +) -> Responsive<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    Responsive::new(f) +} diff --git a/lazy/src/pure/component.rs b/lazy/src/pure/component.rs new file mode 100644 index 00000000..4d952f69 --- /dev/null +++ b/lazy/src/pure/component.rs @@ -0,0 +1,476 @@ +//! Build and reuse custom widgets using The Elm Architecture. +use iced_native::event; +use iced_native::layout::{self, Layout}; +use iced_native::mouse; +use iced_native::overlay; +use iced_native::renderer; +use iced_native::{Clipboard, Length, Point, Rectangle, Shell, Size}; +use iced_pure::widget::tree::{self, Tree}; +use iced_pure::{Element, Widget}; + +use ouroboros::self_referencing; +use std::cell::{Ref, RefCell}; +use std::marker::PhantomData; + +/// A reusable, custom widget that uses The Elm Architecture. +/// +/// A [`Component`] allows you to implement custom widgets as if they were +/// `iced` applications with encapsulated state. +/// +/// In other words, a [`Component`] allows you to turn `iced` applications into +/// custom widgets and embed them without cumbersome wiring. +/// +/// A [`Component`] produces widgets that may fire an [`Event`](Component::Event) +/// and update the internal state of the [`Component`]. +/// +/// Additionally, a [`Component`] is capable of producing a `Message` to notify +/// the parent application of any relevant interactions. +pub trait Component<Message, Renderer> { +    /// The internal state of this [`Component`]. +    type State: Default; + +    /// The type of event this [`Component`] handles internally. +    type Event; + +    /// Processes an [`Event`](Component::Event) and updates the [`Component`] state accordingly. +    /// +    /// It can produce a `Message` for the parent application. +    fn update( +        &mut self, +        state: &mut Self::State, +        event: Self::Event, +    ) -> Option<Message>; + +    /// Produces the widgets of the [`Component`], which may trigger an [`Event`](Component::Event) +    /// on user interaction. +    fn view(&self, state: &Self::State) -> Element<Self::Event, Renderer>; +} + +/// Turns an implementor of [`Component`] into an [`Element`] that can be +/// embedded in any application. +pub fn view<'a, C, Message, Renderer>( +    component: C, +) -> Element<'a, Message, Renderer> +where +    C: Component<Message, Renderer> + 'a, +    C::State: 'static, +    Message: 'a, +    Renderer: iced_native::Renderer + 'a, +{ +    Element::new(Instance { +        state: RefCell::new(Some( +            StateBuilder { +                component: Box::new(component), +                message: PhantomData, +                state: PhantomData, +                element_builder: |_| None, +            } +            .build(), +        )), +    }) +} + +struct Instance<'a, Message, Renderer, Event, S> { +    state: RefCell<Option<State<'a, Message, Renderer, Event, S>>>, +} + +#[self_referencing] +struct State<'a, Message: 'a, Renderer: 'a, Event: 'a, S: 'a> { +    component: +        Box<dyn Component<Message, Renderer, Event = Event, State = S> + 'a>, +    message: PhantomData<Message>, +    state: PhantomData<S>, + +    #[borrows(component)] +    #[covariant] +    element: Option<Element<'this, Event, Renderer>>, +} + +impl<'a, Message, Renderer, Event, S> Instance<'a, Message, Renderer, Event, S> +where +    S: Default, +{ +    fn rebuild_element(&self, state: &S) { +        let heads = self.state.borrow_mut().take().unwrap().into_heads(); + +        *self.state.borrow_mut() = Some( +            StateBuilder { +                component: heads.component, +                message: PhantomData, +                state: PhantomData, +                element_builder: |component| Some(component.view(state)), +            } +            .build(), +        ); +    } + +    fn with_element<T>( +        &self, +        f: impl FnOnce(&Element<'_, Event, Renderer>) -> T, +    ) -> T { +        self.with_element_mut(|element| f(element)) +    } + +    fn with_element_mut<T>( +        &self, +        f: impl FnOnce(&mut Element<'_, Event, Renderer>) -> T, +    ) -> T { +        self.state +            .borrow_mut() +            .as_mut() +            .unwrap() +            .with_element_mut(|element| f(element.as_mut().unwrap())) +    } +} + +impl<'a, Message, Renderer, Event, S> Widget<Message, Renderer> +    for Instance<'a, Message, Renderer, Event, S> +where +    S: 'static + Default, +    Renderer: iced_native::Renderer, +{ +    fn tag(&self) -> tree::Tag { +        tree::Tag::of::<S>() +    } + +    fn state(&self) -> tree::State { +        tree::State::new(S::default()) +    } + +    fn children(&self) -> Vec<Tree> { +        self.rebuild_element(&S::default()); +        self.with_element(|element| vec![Tree::new(element)]) +    } + +    fn diff(&self, tree: &mut Tree) { +        self.rebuild_element(tree.state.downcast_ref()); +        self.with_element(|element| { +            tree.diff_children(std::slice::from_ref(&element)) +        }) +    } + +    fn width(&self) -> Length { +        self.with_element(|element| element.as_widget().width()) +    } + +    fn height(&self) -> Length { +        self.with_element(|element| element.as_widget().height()) +    } + +    fn layout( +        &self, +        renderer: &Renderer, +        limits: &layout::Limits, +    ) -> layout::Node { +        self.with_element(|element| { +            element.as_widget().layout(renderer, limits) +        }) +    } + +    fn on_event( +        &mut self, +        tree: &mut Tree, +        event: iced_native::Event, +        layout: Layout<'_>, +        cursor_position: Point, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +    ) -> event::Status { +        let mut local_messages = Vec::new(); +        let mut local_shell = Shell::new(&mut local_messages); + +        let event_status = self.with_element_mut(|element| { +            element.as_widget_mut().on_event( +                &mut tree.children[0], +                event, +                layout, +                cursor_position, +                renderer, +                clipboard, +                &mut local_shell, +            ) +        }); + +        local_shell.revalidate_layout(|| shell.invalidate_layout()); + +        if !local_messages.is_empty() { +            let mut heads = self.state.take().unwrap().into_heads(); + +            for message in local_messages.into_iter().filter_map(|message| { +                heads +                    .component +                    .update(tree.state.downcast_mut::<S>(), message) +            }) { +                shell.publish(message); +            } + +            self.state = RefCell::new(Some( +                StateBuilder { +                    component: heads.component, +                    message: PhantomData, +                    state: PhantomData, +                    element_builder: |state| { +                        Some(state.view(tree.state.downcast_ref::<S>())) +                    }, +                } +                .build(), +            )); + +            shell.invalidate_layout(); +        } + +        event_status +    } + +    fn draw( +        &self, +        tree: &Tree, +        renderer: &mut Renderer, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +    ) { +        self.with_element(|element| { +            element.as_widget().draw( +                &tree.children[0], +                renderer, +                style, +                layout, +                cursor_position, +                viewport, +            ); +        }); +    } + +    fn mouse_interaction( +        &self, +        tree: &Tree, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        self.with_element(|element| { +            element.as_widget().mouse_interaction( +                &tree.children[0], +                layout, +                cursor_position, +                viewport, +                renderer, +            ) +        }) +    } + +    fn overlay<'b>( +        &'b self, +        tree: &'b mut Tree, +        layout: Layout<'_>, +        renderer: &Renderer, +    ) -> Option<overlay::Element<'b, Message, Renderer>> { +        let overlay = OverlayBuilder { +            instance: self, +            instance_ref_builder: |instance| instance.state.borrow(), +            tree, +            types: PhantomData, +            overlay_builder: |instance, tree| { +                instance +                    .as_ref() +                    .unwrap() +                    .borrow_element() +                    .as_ref() +                    .unwrap() +                    .as_widget() +                    .overlay(&mut tree.children[0], layout, renderer) +            }, +        } +        .build(); + +        let has_overlay = overlay.with_overlay(|overlay| { +            overlay.as_ref().map(overlay::Element::position) +        }); + +        has_overlay.map(|position| { +            overlay::Element::new( +                position, +                Box::new(OverlayInstance { +                    overlay: Some(overlay), +                }), +            ) +        }) +    } +} + +#[self_referencing] +struct Overlay<'a, 'b, Message, Renderer, Event, S> { +    instance: &'a Instance<'b, Message, Renderer, Event, S>, +    tree: &'a mut Tree, +    types: PhantomData<(Message, Event, S)>, + +    #[borrows(instance)] +    #[covariant] +    instance_ref: Ref<'this, Option<State<'a, Message, Renderer, Event, S>>>, + +    #[borrows(instance_ref, mut tree)] +    #[covariant] +    overlay: Option<overlay::Element<'this, Event, Renderer>>, +} + +struct OverlayInstance<'a, 'b, Message, Renderer, Event, S> { +    overlay: Option<Overlay<'a, 'b, Message, Renderer, Event, S>>, +} + +impl<'a, 'b, Message, Renderer, Event, S> +    OverlayInstance<'a, 'b, Message, Renderer, Event, S> +{ +    fn with_overlay_maybe<T>( +        &self, +        f: impl FnOnce(&overlay::Element<'_, Event, Renderer>) -> T, +    ) -> Option<T> { +        self.overlay +            .as_ref() +            .unwrap() +            .borrow_overlay() +            .as_ref() +            .map(f) +    } + +    fn with_overlay_mut_maybe<T>( +        &mut self, +        f: impl FnOnce(&mut overlay::Element<'_, Event, Renderer>) -> T, +    ) -> Option<T> { +        self.overlay +            .as_mut() +            .unwrap() +            .with_overlay_mut(|overlay| overlay.as_mut().map(f)) +    } +} + +impl<'a, 'b, Message, Renderer, Event, S> overlay::Overlay<Message, Renderer> +    for OverlayInstance<'a, 'b, Message, Renderer, Event, S> +where +    Renderer: iced_native::Renderer, +    S: 'static + Default, +{ +    fn layout( +        &self, +        renderer: &Renderer, +        bounds: Size, +        position: Point, +    ) -> layout::Node { +        self.with_overlay_maybe(|overlay| { +            let vector = position - overlay.position(); + +            overlay.layout(renderer, bounds).translate(vector) +        }) +        .unwrap_or_default() +    } + +    fn draw( +        &self, +        renderer: &mut Renderer, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor_position: Point, +    ) { +        self.with_overlay_maybe(|overlay| { +            overlay.draw(renderer, style, layout, cursor_position); +        }); +    } + +    fn mouse_interaction( +        &self, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        self.with_overlay_maybe(|overlay| { +            overlay.mouse_interaction( +                layout, +                cursor_position, +                viewport, +                renderer, +            ) +        }) +        .unwrap_or_default() +    } + +    fn on_event( +        &mut self, +        event: iced_native::Event, +        layout: Layout<'_>, +        cursor_position: Point, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +    ) -> iced_native::event::Status { +        let mut local_messages = Vec::new(); +        let mut local_shell = Shell::new(&mut local_messages); + +        let event_status = self +            .with_overlay_mut_maybe(|overlay| { +                overlay.on_event( +                    event, +                    layout, +                    cursor_position, +                    renderer, +                    clipboard, +                    &mut local_shell, +                ) +            }) +            .unwrap_or_else(|| iced_native::event::Status::Ignored); + +        local_shell.revalidate_layout(|| shell.invalidate_layout()); + +        if !local_messages.is_empty() { +            let overlay = self.overlay.take().unwrap().into_heads(); +            let mut heads = overlay.instance.state.take().unwrap().into_heads(); + +            for message in local_messages.into_iter().filter_map(|message| { +                heads +                    .component +                    .update(overlay.tree.state.downcast_mut::<S>(), message) +            }) { +                shell.publish(message); +            } + +            *overlay.instance.state.borrow_mut() = Some( +                StateBuilder { +                    component: heads.component, +                    message: PhantomData, +                    state: PhantomData, +                    element_builder: |state| { +                        Some(state.view(overlay.tree.state.downcast_ref::<S>())) +                    }, +                } +                .build(), +            ); + +            self.overlay = Some( +                OverlayBuilder { +                    instance: overlay.instance, +                    instance_ref_builder: |instance| instance.state.borrow(), +                    tree: overlay.tree, +                    types: PhantomData, +                    overlay_builder: |instance, tree| { +                        instance +                            .as_ref() +                            .unwrap() +                            .borrow_element() +                            .as_ref() +                            .unwrap() +                            .as_widget() +                            .overlay(tree, layout, renderer) +                    }, +                } +                .build(), +            ); + +            shell.invalidate_layout(); +        } + +        event_status +    } +} diff --git a/lazy/src/pure/responsive.rs b/lazy/src/pure/responsive.rs new file mode 100644 index 00000000..2b62a047 --- /dev/null +++ b/lazy/src/pure/responsive.rs @@ -0,0 +1,381 @@ +use iced_native::event; +use iced_native::layout::{self, Layout}; +use iced_native::mouse; +use iced_native::renderer; +use iced_native::{Clipboard, Length, Point, Rectangle, Shell, Size}; +use iced_pure::horizontal_space; +use iced_pure::overlay; +use iced_pure::widget::tree::{self, Tree}; +use iced_pure::{Element, Widget}; + +use ouroboros::self_referencing; +use std::cell::{RefCell, RefMut}; +use std::marker::PhantomData; +use std::ops::Deref; + +/// A widget that is aware of its dimensions. +/// +/// A [`Responsive`] widget will always try to fill all the available space of +/// its parent. +#[allow(missing_debug_implementations)] +pub struct Responsive<'a, Message, Renderer> { +    view: Box<dyn Fn(Size) -> Element<'a, Message, Renderer> + 'a>, +    content: RefCell<Content<'a, Message, Renderer>>, +} + +impl<'a, Message, Renderer> Responsive<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    /// Creates a new [`Responsive`] widget with a closure that produces its +    /// contents. +    /// +    /// The `view` closure will be provided with the current [`Size`] of +    /// the [`Responsive`] widget and, therefore, can be used to build the +    /// contents of the widget in a responsive way. +    pub fn new( +        view: impl Fn(Size) -> Element<'a, Message, Renderer> + 'a, +    ) -> Self { +        Self { +            view: Box::new(view), +            content: RefCell::new(Content { +                size: Size::ZERO, +                layout: layout::Node::new(Size::ZERO), +                element: Element::new(horizontal_space(Length::Units(0))), +            }), +        } +    } +} + +struct Content<'a, Message, Renderer> { +    size: Size, +    layout: layout::Node, +    element: Element<'a, Message, Renderer>, +} + +impl<'a, Message, Renderer> Content<'a, Message, Renderer> { +    fn update( +        &mut self, +        tree: &mut Tree, +        renderer: &Renderer, +        new_size: Size, +        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, +    ) { +        if self.size == new_size { +            return; +        } + +        self.element = view(new_size); +        self.size = new_size; +        self.layout = self +            .element +            .as_widget() +            .layout(renderer, &layout::Limits::new(Size::ZERO, self.size)); + +        tree.diff(&self.element); +    } + +    fn resolve<R, T>( +        &mut self, +        tree: &mut Tree, +        renderer: R, +        layout: Layout<'_>, +        view: &dyn Fn(Size) -> Element<'a, Message, Renderer>, +        f: impl FnOnce( +            &mut Tree, +            R, +            Layout<'_>, +            &mut Element<'a, Message, Renderer>, +        ) -> T, +    ) -> T +    where +        R: Deref<Target = Renderer>, +    { +        self.update(tree, renderer.deref(), layout.bounds().size(), view); + +        let content_layout = Layout::with_offset( +            layout.position() - Point::ORIGIN, +            &self.layout, +        ); + +        f(tree, renderer, content_layout, &mut self.element) +    } +} + +struct State { +    tree: RefCell<Tree>, +} + +impl<'a, Message, Renderer> Widget<Message, Renderer> +    for Responsive<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    fn tag(&self) -> tree::Tag { +        tree::Tag::of::<State>() +    } + +    fn state(&self) -> tree::State { +        tree::State::new(State { +            tree: RefCell::new(Tree::empty()), +        }) +    } + +    fn width(&self) -> Length { +        Length::Fill +    } + +    fn height(&self) -> Length { +        Length::Fill +    } + +    fn layout( +        &self, +        _renderer: &Renderer, +        limits: &layout::Limits, +    ) -> layout::Node { +        layout::Node::new(limits.max()) +    } + +    fn on_event( +        &mut self, +        tree: &mut Tree, +        event: iced_native::Event, +        layout: Layout<'_>, +        cursor_position: Point, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +    ) -> event::Status { +        let state = tree.state.downcast_mut::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget_mut().on_event( +                    tree, +                    event, +                    layout, +                    cursor_position, +                    renderer, +                    clipboard, +                    shell, +                ) +            }, +        ) +    } + +    fn draw( +        &self, +        tree: &Tree, +        renderer: &mut Renderer, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +    ) { +        let state = tree.state.downcast_ref::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget().draw( +                    tree, +                    renderer, +                    style, +                    layout, +                    cursor_position, +                    viewport, +                ) +            }, +        ) +    } + +    fn mouse_interaction( +        &self, +        tree: &Tree, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        let state = tree.state.downcast_ref::<State>(); +        let mut content = self.content.borrow_mut(); + +        content.resolve( +            &mut state.tree.borrow_mut(), +            renderer, +            layout, +            &self.view, +            |tree, renderer, layout, element| { +                element.as_widget().mouse_interaction( +                    tree, +                    layout, +                    cursor_position, +                    viewport, +                    renderer, +                ) +            }, +        ) +    } + +    fn overlay<'b>( +        &'b self, +        tree: &'b mut Tree, +        layout: Layout<'_>, +        renderer: &Renderer, +    ) -> Option<overlay::Element<'b, Message, Renderer>> { +        let state = tree.state.downcast_ref::<State>(); + +        let overlay = OverlayBuilder { +            content: self.content.borrow_mut(), +            tree: state.tree.borrow_mut(), +            types: PhantomData, +            overlay_builder: |content, tree| { +                content.update( +                    tree, +                    renderer, +                    layout.bounds().size(), +                    &self.view, +                ); + +                let content_layout = Layout::with_offset( +                    layout.position() - Point::ORIGIN, +                    &content.layout, +                ); + +                content.element.as_widget().overlay( +                    tree, +                    content_layout, +                    renderer, +                ) +            }, +        } +        .build(); + +        let has_overlay = overlay.with_overlay(|overlay| { +            overlay.as_ref().map(overlay::Element::position) +        }); + +        has_overlay +            .map(|position| overlay::Element::new(position, Box::new(overlay))) +    } +} + +impl<'a, Message, Renderer> From<Responsive<'a, Message, Renderer>> +    for Element<'a, Message, Renderer> +where +    Renderer: iced_native::Renderer + 'a, +    Message: 'a, +{ +    fn from(responsive: Responsive<'a, Message, Renderer>) -> Self { +        Self::new(responsive) +    } +} + +#[self_referencing] +struct Overlay<'a, 'b, Message, Renderer> { +    content: RefMut<'a, Content<'b, Message, Renderer>>, +    tree: RefMut<'a, Tree>, +    types: PhantomData<Message>, + +    #[borrows(mut content, mut tree)] +    #[covariant] +    overlay: Option<overlay::Element<'this, Message, Renderer>>, +} + +impl<'a, 'b, Message, Renderer> Overlay<'a, 'b, Message, Renderer> { +    fn with_overlay_maybe<T>( +        &self, +        f: impl FnOnce(&overlay::Element<'_, Message, Renderer>) -> T, +    ) -> Option<T> { +        self.borrow_overlay().as_ref().map(f) +    } + +    fn with_overlay_mut_maybe<T>( +        &mut self, +        f: impl FnOnce(&mut overlay::Element<'_, Message, Renderer>) -> T, +    ) -> Option<T> { +        self.with_overlay_mut(|overlay| overlay.as_mut().map(f)) +    } +} + +impl<'a, 'b, Message, Renderer> overlay::Overlay<Message, Renderer> +    for Overlay<'a, 'b, Message, Renderer> +where +    Renderer: iced_native::Renderer, +{ +    fn layout( +        &self, +        renderer: &Renderer, +        bounds: Size, +        position: Point, +    ) -> layout::Node { +        self.with_overlay_maybe(|overlay| { +            let vector = position - overlay.position(); + +            overlay.layout(renderer, bounds).translate(vector) +        }) +        .unwrap_or_default() +    } + +    fn draw( +        &self, +        renderer: &mut Renderer, +        style: &renderer::Style, +        layout: Layout<'_>, +        cursor_position: Point, +    ) { +        self.with_overlay_maybe(|overlay| { +            overlay.draw(renderer, style, layout, cursor_position); +        }); +    } + +    fn mouse_interaction( +        &self, +        layout: Layout<'_>, +        cursor_position: Point, +        viewport: &Rectangle, +        renderer: &Renderer, +    ) -> mouse::Interaction { +        self.with_overlay_maybe(|overlay| { +            overlay.mouse_interaction( +                layout, +                cursor_position, +                viewport, +                renderer, +            ) +        }) +        .unwrap_or_default() +    } + +    fn on_event( +        &mut self, +        event: iced_native::Event, +        layout: Layout<'_>, +        cursor_position: Point, +        renderer: &Renderer, +        clipboard: &mut dyn Clipboard, +        shell: &mut Shell<'_, Message>, +    ) -> event::Status { +        self.with_overlay_mut_maybe(|overlay| { +            overlay.on_event( +                event, +                layout, +                cursor_position, +                renderer, +                clipboard, +                shell, +            ) +        }) +        .unwrap_or_else(|| iced_native::event::Status::Ignored) +    } +} | 
