Cannot move out of an `Arc`

Hi all I am getting "cannot move out of an Arc in here:

error[E0507]: cannot move out of an `Arc`
  --> src/fetch/fetch_job.rs:94:18
   |
94 |             .zip(lock.clone().uri_iter)
   |                  ^^^^^^^^^^^^^^^^^^^^^ cannot move out of an `Arc`
        let mut lock = Arc::new(self.clone());
        let requests: Vec<_> = (0..self.chunk)
            .zip(lock.clone().uri_iter)

not sure how to fix this.

2 Likes

You can use *lock to dereference the Arc and get at the value inside it. Then you can clone that value, instead of cloning the Arc:

.zip((*lock).clone().uri_iter)

Though it might make more sense in this case to clone only the one field you need, instead of the whole struct:

.zip(lock.uri_iter.clone())
1 Like
error[E0507]: cannot move out of borrowed content
  --> src/fetch/fetch_job.rs:94:18
   |
94 |             .zip((*lock).clone().uri_iter)
   |                  ^^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of borrowed content
        let mut lock = Arc::new(self.clone());
        let requests: Vec<_> = (0..self.chunk)
            .zip((*lock).clone().uri_iter)
            .map(move |(_, uri)| {

What is the type of self? Is it a reference? (Does this function take an &self argument?) Does the Self type implement Clone?

impl<'a, S, I> WeatherStream<'a, S, I>
where
    S: StoreWeather ,
    I: Iterator<Item = Uri> + Send,
{
    fn new(uri_iter: I, chunk: u64, duration: Duration, storage_client: S) -> Self {
        Self {
            uri_iter,
            chunk,
            interval: Interval::new_interval(duration),
            fetch_future: None,
            storage_client: Arc::new(Mutex::new(Box::new(storage_client))),
            time_pass: TimePass::Ready,
        }
    }

    //change number of requests to a parameter.
    pub fn fetch_chunk(&self) -> impl Future<Item = bool, Error = ()> {
        let client = build_https_client().unwrap(); //TODO catch error
        let chunk = Arc::new(self.chunk);
        let mut lock = Arc::new(self.clone());
        let requests: Vec<_> = (0..self.chunk)
            .zip(lock.uri_iter.clone())
            .map(move |(_, uri)| {
                client
                    .clone()
                    .get(uri)
                    .map(|res| {
                        println!("Response: {}", res.status());
                        println!("Headers: {:#?}", res.headers());
                    })
                    .map_err(|_| ())
            })
            .collect();
        future::join_all(requests)
            .map(move |res: Vec<()>| res.len() as u64 == *chunk)
            .map_err(|_| ())
    }
}

No self does not implement clone, that is why I am using Arc

Then you should probably clone the member variable (uri_iter) instead of trying to clone the unclonable inner lock.

            .zip(lock.uri_iter.clone())
error[E0599]: no method named `clone` found for type `I` in the current scope
  --> src/fetch/fetch_job.rs:94:32
   |
94 |             .zip(lock.uri_iter.clone())
   |                                ^^^^^
   |
   = help: items from traits can only be used if the trait is implemented and in scope
   = note: the following trait defines an item `clone`, perhaps you need to implement it:
           candidate #1: `std::clone::Clone`
   = help: did you mean `cloned`?

but I did implement it:

#[derive(Clone,Copy)]
pub struct DarkSky {
    pub base: &'static str,
    pub coordinates: &'static str,
    pub start: DateTime<Local>,
    pub end: DateTime<Local>,
    pub current: DateTime<Local>,
}


impl DarkSky {
    pub fn new(
        base: &'static str,
        coordinates: &'static str,
        start: DateTime<Local>,
        end: DateTime<Local>,
    ) -> Self {
        Self {
            base,
            coordinates,
            start,
            end,
            current: start,
        }
    }
}

impl Iterator for DarkSky {
    type Item = hyper::Uri;

    fn next(&mut self) -> Option<Self::Item> {
        let date = self.current - chrono::Duration::days(1);
        if date > self.end {
            None
        } else {
            self.current = date.clone();
            Some(
                format!("{}/{} {}", self.base, self.coordinates, date.timestamp())
                    .parse::<hyper::Uri>()
                    .unwrap(),
            )
        }
    }
}

self here has type &WeatherStream. When you write self.clone(), since it can't clone the WeatherStream, it clones the &WeatherStream, returning an identical &WeatherStream value. You then put this in an Arc, creating an Arc<&WeatherStream>. The Arc doesn't add anything here. (I'm also not clear why chunk is an Arc.)

If you want to be able to create multiple copies of the uri_iter field, you will at least need to require a Clone bound on its type I. Or perhaps you can instead take &mut self and return a future that captures a mutable reference to self.uri_iter so you do not need to clone it.

Or your function could take self: Arc<Self> if you want it to be able to return a future with shared ownership of the whole WeatherStream. In this case you'll need to add some more Mutex or RwLock for fields like the iterator that need to be mutable.

4 Likes

Ok makes sense I will try some things around and will let you know of the progress

Okay so here is what I did:

    //change number of requests to a parameter.
    pub fn fetch_chunk(self: Arc<Self>) -> impl Future<Item = bool, Error = ()> + 'a {
        let client = build_https_client().unwrap(); //TODO catch error
        let iter = self.clone().uri_iter.lock().unwrap();
        let requests: Vec<_> = (0..self.chunk)
            .zip(*iter)
            .map(move |(_, uri)| {
                client
                    .clone()
                    .get(uri)
                    .map(|res| {
                        println!("Response: {}", res.status());
                        println!("Headers: {:#?}", res.headers());
                    })
                    .map_err(|_| ())
            })
            .collect();
        future::join_all(requests)
            .map(move |res: Vec<()>| res.len() as u64 == self.clone().chunk)
            .map_err(|_| ())
    }
}

impl<'a, S, I> Stream for WeatherStream<'a, S, I>
where
    S: StoreWeather + 'a,
    I: Iterator<Item = Uri> + Send + 'a,
{
    type Item = bool;
    type Error = ();

    fn poll(&mut self) -> Poll<Option<Self::Item>, ()> {
        loop {
            match self.time_pass {
                TimePass::Ready => {
                    if let Some(_) = self.fetch_future {
                        try_ready!(self.fetch_future.poll().map_err(|_| ()));
                    } else {
                        self.fetch_future: Option<Box<Future<Item=bool, Error=()> + 'a + Send>> = Some(Box::new(self.fetch_chunk()));
                        try_ready!(self.fetch_future.poll().map_err(|_| ()));
                    }
                    self.time_pass = TimePass::Waiting;
                    self.fetch_future = None;
                }
                TimePass::Waiting => {
                    match self.interval.poll() {
                        Ok(Async::Ready(value)) => {
                            self.time_pass = TimePass::Ready;
                            return Ok(Async::Ready(Some(false)));
                        }
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => return Err(()),
                    }
                }
            };
        }
    }
}

and I get this:

error[E0599]: no method named `fetch_chunk` found for type `std::sync::Arc<&mut fetch::fetch_job::WeatherStream<'a, S, I>>` in the current scope
   --> src/fetch/fetch_job.rs:126:128
    |
126 |                         self.fetch_future: Option<Box<Future<Item=bool, Error=()> + 'a + Send>> = Some(Box::new(Arc::new(self).fetch_chunk()));
    |                                                                                                                                ^^^^^^^^^^^

error: aborting due to previous error