Workers

Workers are simply components that don't have any widgets. They can be quite useful for applications that need to handle long tasks while remaining responsive. In particular, they are suitable for CPU-bound tasks which need to be handled one at the time because they run on a different thread.

Implementing a worker

A worker is implemented similarly to a component by using the Worker trait. Since workers don't have widgets, you don't need to provide a Widgets type.

#[derive(Debug)]
enum AppMsg {
    Increment,
    Decrement,
}

#[derive(Debug)]
enum AsyncHandlerMsg {
    DelayedIncrement,
    DelayedDecrement,
}

struct AsyncHandler;

impl Worker for AsyncHandler {
    type Init = ();
    type Input = AsyncHandlerMsg;
    type Output = AppMsg;

    fn init(_init: Self::Init, _sender: ComponentSender<Self>) -> Self {
        Self
    }

    fn update(&mut self, msg: AsyncHandlerMsg, sender: ComponentSender<Self>) {
        // Simulating heavy CPU-bound task
        std::thread::sleep(Duration::from_secs(1));

        // Send the result of the calculation back
        match msg {
            AsyncHandlerMsg::DelayedIncrement => sender.output(AppMsg::Increment),
            AsyncHandlerMsg::DelayedDecrement => sender.output(AppMsg::Decrement),
        }
        .unwrap()
    }
}

Workers are constructed similarly to components, too. Use the provided builder to retrieve a WorkerController.

    fn init(_: (), root: Self::Root, sender: ComponentSender<Self>) -> ComponentParts<Self> {
        let model = AppModel {
            counter: 0,
            worker: AsyncHandler::builder()
                .detach_worker(())
                .forward(sender.input_sender(), identity),
        };

        let widgets = view_output!();

        ComponentParts { model, widgets }
    }

Through the WorkerController, you can send and receive messages from the worker. The worker's update function will run on a separate thread, so your other components won't be blocked.

struct AppModel {
    counter: u8,
    worker: WorkerController<AsyncHandler>,
}