Here is a very simplified code where I am using i8
and Vec::iter
just for the sake of an example, but the actual types and iterators are more involved (so &i8
or Vec::iter
specific solutions are of little use).
Lets say
struct Foo(Vec<RwLock<Vec<i8>>>);
and I want to flat_map
on the inner vectors:
fn iter(&self) -> impl Iterator<Item=&i8>
Below code does not compile because of temporary references and lifetimes:
impl Foo {
fn iter(&self) -> impl Iterator<Item=&i8> {
self.0.iter().flat_map(|item| {
item.read().unwrap().iter()
})
}
}
See this link to playground for the compilation error.
However with a bit of unsafe
code I can do:
use std::sync::{RwLock, RwLockReadGuard};
struct Foo(Vec<RwLock<Vec<i8>>>);
impl Foo {
fn iter(&self) -> impl Iterator<Item = &i8> {
self.0.iter().flat_map(|item| {
let guard = item.read().unwrap();
let xs: &Vec<i8> = unsafe { change_lifetime_const(&*guard) };
GuardIter {
_guard: guard,
inner: xs.iter(),
}
})
}
}
unsafe fn change_lifetime_const<'a, 'b, T>(x: &'a T) -> &'b T {
&*(x as *const T)
}
struct GuardIter<'a, I> {
_guard: RwLockReadGuard<'a, Vec<i8>>,
inner: I,
}
impl<'a, I, T> Iterator for GuardIter<'a, I>
where
I: Iterator<Item = T>,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.inner.next()
}
}
My questions:
- Is the above
unsafe
code correct? or, am I missing something? - Any way this code can be improved?
- Or any better way to solve this problem?
Again, as a reminder, i8
and Vec::iter
here are just for the sake of an example, but the actual types and iterators are more involved.