Iced subscription using Recipe/stream taking values from a flume Receiver

Hi,

Trying to forward a stream of (midi and clock) events to a simple Iced UI and I'm having a few problems.
So far things seem very upset due to Iced wanting 'static lifetime, but also I'm relatively new at rust so maybe making some fundament errors with pinning and lifetimes and such. I'm looking at the iced/download.rs example and the Recipe constructor for making a bridge from the Reciever (channel) but I guess I'm just missing something obvious/fundamental (I hope).

The relevant bits of my code are (this is all brutally copied from the example, names are as such):

struct Example<'a> {
    processed_rx_stream: BoxStream<'a, Progress>,
    _pin: PhantomPinned,
}

pub struct Download<'a, I> {
    id: I,
    processed_rx_stream: BoxStream<'a, Progress>,
    _pin: PhantomPinned,
}

impl<H, I, T> iced_native::subscription::Recipe<H, I> for Download<'_, T>
    where
        T: 'static + Hash + Copy + Send,
        H: Hasher,
{
    type Output = (T, Progress);

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, I>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        self.processed_rx_stream
    }
}

impl Application for Example<'static> {
    fn new(_flags: ()) -> (Example<'static>, Command<Self::Message>) {
        use std::thread;
        let (processed_send, processed_rx) = flume::unbounded::<Progress>();
        thread::spawn(move || loop {
            thread::sleep(Duration::from_millis(200));
            processed_send.send(Progress::Tick);
        });

        let st = processed_rx.into_stream();
        let processed_rx_stream = Box::pin(st);
        let (panes, _) = pane_grid::State::new(Content::new(0));
        (Example {
            processed_rx_stream,
            _pin: PhantomPinned,
        }, Command::none())
    }
}

I have errors like:

    = note: expected `Pin<Box<(dyn iced::futures::Stream<Item = Progress> + std::marker::Send + 'static)>>`
               found `Pin<Box<dyn iced::futures::Stream<Item = Progress> + std::marker::Send>>`

I guess the basic question is how can I make my stream 'static so it fits with the return type below?

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, I>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {

Can you please post the full error?

Hi,
So I've moved past that error (by just changing the 'a to 'static on the impl of the Recipe, although I'm not sure I quite understand why that worked), and onto another issue.

Fundamentally, I think my problem now is:

I am trying to use a single Receiver (processed_rx) as the source of a Subscription in Iced. This seems to want me to create a Subscription from the contents of self: Example, using iced::Subscription::from_recipe. I just don't understand how I can "move" the processed_rx as I create the Subscription.

My relevant bits of code now are:

struct Example<'a> {
    recipe1: iced::Subscription<Progress>,
    _pin: PhantomPinned,
}

pub struct Download<'a, I> {
    id: I,
    processed_rx_stream: BoxStream<'a, Progress>,
    _pin: PhantomPinned,
}

impl<H, I, T> iced_native::subscription::Recipe<H, I> for Download<'static, T>
    where
        T: 'static + Hash + Copy + Send,
        H: Hasher,
{
    type Output = (Progress);

    fn hash(&self, state: &mut H) {
        struct Marker;
        std::any::TypeId::of::<Marker>().hash(state);

        self.id.hash(state);
    }

    fn stream(
        self: Box<Self>,
        _input: futures::stream::BoxStream<'static, I>,
    ) -> futures::stream::BoxStream<'static, Self::Output> {
        self.processed_rx_stream
    }
}

impl Application for Example<'static> {
    fn new(_flags: ()) -> (Example<'static>, Command<Self::Message>) {
        use std::thread;
        let (processed_send, processed_rx) = flume::unbounded::<Progress>();
        thread::spawn(move || loop {
            thread::sleep(Duration::from_millis(200));
            processed_send.send(Progress::Tick);
        });

        let st = processed_rx.into_stream();
        let processed_rx_stream: BoxStream<'static, Progress> = Box::pin(st);
        let download = Download {
            id: 0,
            processed_rx_stream,
            _pin: PhantomPinned,
        };
        let recipe1: iced::Subscription<Progress> = iced::Subscription::from_recipe(download);
        // let processed_rx_stream = st.boxed();
        let (panes, _) = pane_grid::State::new(Content::new(0));
        (Example {
            recipe1,
            _pin: PhantomPinned,
        }, Command::none())
}

    fn subscription(&self) -> Subscription<Message> {
        Subscription::batch(vec!(
            self.recipe1.map(|x| {Message::Tick})
            ,
        ))
    }
}

and the error now, which I understand but have no idea how to fix is

error[E0507]: cannot move out of `self.recipe1` which is behind a shared reference
   --> src\main.rs:212:13
    |
212 |             self.recipe1.map(|x| {Message::Tick})
    |             ^^^^^^^^^^^^ move occurs because `self.recipe1` has type `iced_futures::subscription::Subscription<iced_native::Hasher, (iced_native::Event, Status), Progress>`, which does not implement the `Copy` trait

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.