Issue implementing a subscription channel

Hello!

I was trying to implement a subscription allowing for two-way communication as described in the docs.

In my attempt, the main application implementation creates a subscription that sends a message “Ready” along with a Sender<Order> transmitter to send follow up requests. That message is supposed to be received in the update function.

However, the message never appears. A stripped-down sample of my code is shown below:

use std::{
    any::TypeId,
    sync::mpsc::{self, Receiver, Sender},
};

use iced::{
    executor, subscription,
    widget::{column, text},
    Application, Command, Theme,
};

struct Viewer;

enum Order {}

#[derive(Clone, Debug)]
enum Message {
    SubscriptionReady(Sender<Order>),
}

impl Application for Viewer {
    type Executor = executor::Default;

    type Message = Message;

    type Theme = Theme;

    type Flags = ();

    fn new(_: Self::Flags) -> (Self, iced::Command<Self::Message>) {
        return (Viewer, Command::none());
    }

    fn title(&self) -> String {
        return "Subscription confusion".to_string();
    }

    fn update(&mut self, message: Self::Message) -> iced::Command<Self::Message> {
        match message {
            Message::SubscriptionReady(_) => println!("Subscription ready!"), // NEVER PRINTED
        };

        Command::none()
    }

    fn view(&self) -> iced::Element<'_, Self::Message, Self::Theme, iced::Renderer> {
        column![text("Hello, world.")].into()
    }

    fn subscription(&self) -> iced::Subscription<Self::Message> {
        struct Worker;
        enum State {
            Starting,
            Ready(Receiver<Order>),
        }

        subscription::channel(TypeId::of::<Worker>(), 10, |mut output| async move {
            let mut state = State::Starting;

            loop {
                match state {
                    State::Starting => {
                        let (tx, rx) = mpsc::channel();
                        output.try_send(Message::SubscriptionReady(tx)).unwrap();
                        state = State::Ready(rx);
                    }
                    State::Ready(_) => {
                        // calculations...
                    }
                }
            }
        })
    }
}

fn main() {
    Viewer::run(iced::Settings::default()).unwrap();
}

How can I fix this issue?

Thanks!

That loop may be spinning endlessly. Blocking in an async context is not allowed! You need to return control to the runtime.

Try simply waiting forever here, for now:

State::Ready(_) => {
    futures::future::pending().await;
}
1 Like

Thanks for the reply!

Does that mean the docs are inaccurate? Also, how can I check for messages from the main thread if I cannot loop?

You can loop, just not without control.

The docs use the async version of an mpsc channel, which can be read and written to asynchronously. It’s all there.

1 Like

After reading about async and await, I figured it out. Thanks for your help!