Reputation: 83
I have a Vec<Rc<RefCell<MyStruct>>>
member on a struct and I have an external library function that expects to be handed an Iterator
with an Item
that is a &'a mut dyn LibTrait
which I have as a member inside MyStruct
. I can't figure out how to get a raw &mut
from out of the Rc<RefCell<MyStruct>>
in my iterator even though I know the Vec
member that holds it will stick around for longer than either the iterator or the function that gets passed the iterator.
The library looks like this:
struct Lib {}
trait LibTrait {
fn run(&mut self);
}
impl Lib {
pub fn lib_func<'a, Iter>(&mut self, trait_iter: Iter)
where
Iter: Iterator<Item = &'a mut dyn LibTrait>,
{
...
}
}
Here's my latest attempt where I tried to create a temp Vec to hold RefMut's to all the MyStructs so that those refs are owned for the whole time that the &mut would be inside the iterator and lib function. (This code complains about "cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements".)
struct TraitImpl {
dummy: f32,
}
impl LibTrait for TraitImpl {
fn run(&mut self) {
self.dummy += 1.0;
}
}
struct MyStruct {
my_impl: TraitImpl,
num: f32,
}
type MutStructSlice<'a> = &'a mut [&'a mut MyStruct];
struct TraitIterator<'a> {
my_structs: MutStructSlice<'a>,
index: usize,
}
impl<'a> TraitIterator<'a> {
fn new(my_structs: MutStructSlice<'a>) -> Self {
Self {
my_structs,
index: 0,
}
}
}
impl<'a> Iterator for TraitIterator<'a> {
type Item = &'a mut dyn LibTrait;
fn next(&mut self) -> Option<&'a mut dyn LibTrait> {
if self.index >= self.my_structs.len() {
return None;
}
Some(&mut self.my_structs[self.index].my_impl)
}
}
struct Data {
data: Vec<Rc<RefCell<MyStruct>>>,
lib: Lib,
}
impl Data {
fn do_stuff(&mut self) {
let mut struct_refs: Vec<RefMut<MyStruct>> = self
.data
.iter_mut()
.map(|s_rc| s_rc.borrow_mut())
.collect();
let mut structs_raw_refs: Vec<&mut MyStruct> =
struct_refs.iter_mut().map(|s_ref| &mut **s_ref).collect();
self.lib.lib_func(TraitIterator::new(&mut structs_raw_refs));
}
}
Here's the playground
Is there some way around this given that I can't change the library and I need to have Rc<RefCell<>>'s to the data?
Upvotes: 0
Views: 396
Reputation: 60051
I think you're overcomplicating this. You don't need a custom iterator, you can do this with .map()
:
fn do_stuff(&mut self) {
let mut struct_refs: Vec<RefMut<MyStruct>> = self.data
.iter_mut()
.map(|s_rc| s_rc.borrow_mut())
.collect();
self.lib.lib_func(struct_refs.iter_mut().map(|s_ref| &mut s_ref.my_impl as &mut dyn LibTrait));
}
You get the error you did because implementing Iterator
for &mut T
is inherently unsafe. See How to implement Iterator yielding mutable references.
Upvotes: 1