I'm playing with Rc<RefCell<dyn Obj>>
and came up with a behavior I don't understand.
Basically, in a struct, I own a collection of Rc<RefCell<dyn Obj>>
. I can push an item of type Concrete
implementing Obj
in the collection, and get a Rc<RefCell<Concrete>>
of it. Then I need functions to test whether a given Rc<RefCell<Concrete>>
or a given Rc<RefCell<dyn Obj>>
belongs to the collection (not the value, the refcell !).
I came up with the following playground :
use std::{rc::Rc, cell::RefCell};
// Trait and implementing concrete type
pub trait Obj {}
struct Concrete {}
impl Obj for Concrete {}
// Structure owning a collection of Rc<RefCell<dyn Obj>>
struct V {
v: Vec<Rc<RefCell<dyn Obj>>>
}
impl V {
fn new() -> Self {
V{v: Vec::new()}
}
// Push a an item in the collection and get a Rc<RefCell<T>> to manipulate it
fn push<T: Obj + 'static>(&mut self, obj: T) -> Rc<RefCell<T>> {
let obj = Rc::new(RefCell::new(obj));
self.v.push(Rc::clone(&obj) as Rc<RefCell<dyn Obj>>);
obj
}
// Check whether a Rc<RefCell<T:Obj>> is in the collection
fn has_concrete_obj<T: Obj + 'static>(&self, candidate: &Rc<RefCell<T>>) -> bool {
for obj in self.v.iter() {
if Rc::ptr_eq(&obj, &(Rc::clone(candidate) as Rc<RefCell<dyn Obj>>)) {
return true;
}
}
false
}
// Check whether a Rc<RefCell<dyn Obj>> is in the collection
fn has_dyn_obj(&self, candidate: &Rc<RefCell<dyn Obj>>) -> bool {
for obj in self.v.iter() {
if Rc::ptr_eq(&obj, &candidate) {
return true;
}
}
false
}
}
fn main() {
let mut v = V::new();
let obj = v.push(Concrete{});
// here, we could use obj with obj.borrow().fn_conrete() or obj.borrow_mut().fn_concrete_mut()
// Basic tests that should pass
assert!(v.has_concrete_obj(&obj));
assert!(v.has_dyn_obj(&(Rc::clone(&obj) as Rc<RefCell<dyn Obj>>)));
assert!(v.has_dyn_obj(v.v.iter().next().unwrap()));
}
It works as intended in the playground (all asserts pass), but not anymore when I run the exact same sample code on my computer : the second assert fails, whereas the first and the third pass. I don't get why, the first and the second doing basically pretty much the same thing...