Comparison between two Rc<RefCell<dyn Obj>> - Unconsistent behavior

153 Views Asked by At

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...

0

There are 0 best solutions below