Jomy
Jomy

Reputation: 558

Cannot return reference to temporary value with RwLock and iterators

I haven't found an answer to this in other questions.

I have reduced my problem to the following:

use std::sync::RwLock;

pub fn main() {
    iter_lock().for_each(|v| {
        println!("{}", v);
    });
}

fn get_lock<'a>() -> &'a RwLock<Vec<u32>> {
    static mut lock: RwLock<Vec<u32>> = RwLock::new(Vec::new());
    unsafe { &lock }
}

fn iter_lock<'a>() -> impl std::iter::Iterator<Item = &'a u32> {
    get_lock().read().unwrap().iter()
}

playground

The code above will not compile and give the following error:

error[E0515]: cannot return reference to temporary value
  --> src/main.rs:15:5
   |
15 |     get_lock().read().unwrap().iter()
   |     --------------------------^^^^^^^
   |     |
   |     returns a reference to data owned by the current function
   |     temporary value created here
   |
   = help: use `.collect()` to allocate the iterator

How can I solve this issue? I'm not afraid of using unsafe code, so unsafe suggestions are also welcome.

Upvotes: 0

Views: 564

Answers (1)

Vladimir
Vladimir

Reputation: 292

You can try something like this:

use std::sync::{RwLock, RwLockReadGuard};

pub fn main() {
    let data = Data::new(&[1, 2, 3]);

    data.iter().for_each(|x| println!("{:?}", x));
}


struct Data {
    inner: RwLock<Vec<u32>>,
}

impl Data {
    fn new(vec: &[u32]) -> Self {
        Self {
            inner: RwLock::new(vec.to_vec()),
        }
    }

    fn iter(&self) -> Iter<'_> {
        let d = self.inner.read().unwrap();
        Iter::new(d)
    }
}

struct Iter<'a> {
    inner: RwLockReadGuard<'a, Vec<u32>>,
    current_index: usize,
}

impl<'a> Iter<'a> {
    pub fn new(inner: RwLockReadGuard<'a, Vec<u32>>) -> Iter<'a> {
        Self {
            inner,
            current_index: 0,
        }
    }
}

impl Iterator for Iter<'_> {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current_index >= self.inner.len() {
            return None;
        }

        let item = &self.inner[self.current_index];
        self.current_index += 1;
        Some(*item)
    }
}

Upvotes: 1

Related Questions