Lifetime problems when using iced::Component

Hi there!

I am trying to use the trait iced::Component. I had a look a the example but my use case is not covered there.

When using the trait I have to implement view which has the type signature

    fn view(&self, state: &Self::State) -> Element<'_, Self::Event, Theme, Renderer>;

So, according to Rust’s lifetime elision rules, &selfand &Self::State are assigned two different lifetimes (e.g., 'a and 'b, respectively). The resulting Elementcan only contain data from &'a self, not from &'b Self::State.

Is this intentional? The resulting widgets can only reference data from self, not from Self::State?

If yes, how can I circumvent this limitation and use iced::Component correctly?

I haven’t tried the Component trait myself but you’re right, all the examples I’ve found (which are not that many by the way, just the one included in Iced and a couple more in Github) either don’t have an internal state or they use it during view but don’t need to return references to parts of it.

What exactly is your use case? What would be stored in your component’s internal state that you would need to reference directly from the final widget?

My component contains a canvas and a few buttons. The geometry drawn by my program on the canvas is cached. I am trying to make this cache part of the component’s local state because I do not need it to be part of the global application state.

The code looks something like this (simplified):

struct MyComponent<Message> {
    on_close: Box<dyn Fn() -> Message>,
}

struct MyComponentState {
    my_canvas_state: MyCanvasState
}

pub enum MyComponentEvent {
    MyCanvas(MyProgramMessage),
}

impl<Message> Component<Message> for MyComponent<Message> {
    type State = MyComponentState;
    type Event = MyComponentEvent;;

    fn update(&mut self, state: &mut Self::State, event: Self::Event) -> Option<Message> {
        //...
        None
    }

    fn view(&self, state: &Self::State) -> Element<Self::Event> {
        let element = Canvas::new(MyProgram {
            my_canvas_state: &my_canvas_state,
        })
        .into();

        element
            .map(MyComponentEvent::MyCanvas)
            .into()
    }
}

struct MyCanvasState {
    geometry_cache: iced::widget::canvas::Cache
}

struct MyProgram<'a>' {
    my_canvas_state: &'a MyCanvasState'
}

impl<'a> Program<MyProgramMessage> for MyProgram<'a> {
    //...
}

Hmm yes, this sounds like a perfectly valid use case. I don’t know what’s the proper way to fix this, or if maybe Iced hasn’t considered this scenario. It sounds like your options at the moment are: make the geometry part of the global app state, or clone the geometry from the internal state on every view.