Question: clone cost in subscription

My question is based on download_progress example.

First, fn subscription() is called repeatedly while task is running, is this right?

If so, subscription::unfold (called from fn subscription in download example) would be called repeatedly.

pub fn file<I: 'static + Hash + Copy + Send + Sync, T: ToString>(
    id: I,
    url: T,
) -> iced::Subscription<(I, Progress)> {
    subscription::unfold(id, State::Ready(url.to_string()), move |state| {
        download(id, state)
    })
}

I noticed that this takes url to make a String for initial value (State::Ready in second parameter). This may cause a cost for cloning a value required for the task every time, even if it is used only for first time, is this right?

If so, Iā€™m thinking of using Arc to avoid clone. Is this a right approach?

use std::sync::Arc;
use serde_json::Value;

struct Params {
    url: String,
    body: Value,  // JSON to post to a server
    path: String, // local file path to save the responce
}

// same as State in download_progress example
// except for the element of Ready
pub enum State {
    Ready(Params),
    Downloading {
        response: reqwest::Response,
        total: u64,
        downloaded: u64,
    },
    Finished,
}

struct DownloadTask {
    params: Arc<Params>
}

impl DownloadTask {
    fn new(params: Params) -> Self;

    fn download(&self) -> iced::Subscription<(I, Progress)> {
        let init = State::Ready(self.params.clone());
        subscription::unfold(id, init, move |state| {
            // implementation
        })
    }
}

Hi,

I think your approach of using Arc to avoid the cost of cloning is correct.
Recently, I worked on a Bluetooth app and had similar problems with using subscriptions in more complex scenarios. I have tried a lot of different ideas and depending on the specific use case, another solution could be a combination of the download example and the web server example. I have created a little show case project here: GitHub - kunerd/iced_subscription_test.

1 Like