I want to test if two objects of type Rc<Trait>
contain the same instance of a concrete type, so I compare pointers to the objects inside Rc
for equality. It seems to work correctly if all the code resides in the same crate but fails when multiple crates are involved.
In Rust 1.17 the function Rc::ptr_eq
was added, which as of Rust 1.31, exhibits the same cross-crate issue as the manual pointer comparison used in this question.
This is the implementation of crate mcve
(src/lib.rs
):
use std::rc::Rc;
pub trait ObjectInterface {}
pub type Object = Rc<ObjectInterface>;
pub type IntObject = Rc<i32>;
impl ObjectInterface for i32 {}
/// Test if two Objects refer to the same instance
pub fn is_same(left: &Object, right: &Object) -> bool {
let a = left.as_ref() as *const _;
let b = right.as_ref() as *const _;
let r = a == b;
println!("comparing: {:p} == {:p} -> {}", a, b, r);
r
}
pub struct Engine {
pub intval: IntObject,
}
impl Engine {
pub fn new() -> Engine {
Engine {
intval: Rc::new(42),
}
}
pub fn run(&mut self) -> Object {
return self.intval.clone();
}
}
I test the implementation with the following code (tests/testcases.rs
):
extern crate mcve;
use mcve::{is_same, Engine, Object};
#[test]
fn compare() {
let mut engine = Engine::new();
let a: Object = engine.intval.clone();
let b = a.clone();
assert!(is_same(&a, &b));
let r = engine.run();
assert!(is_same(&r, &a));
}
Running the test results in the following output:
comparing: 0x7fcc5720d070 == 0x7fcc5720d070 -> true
comparing: 0x7fcc5720d070 == 0x7fcc5720d070 -> false
thread 'compare' panicked at 'assertion failed: is_same(&r, &a)'
How is it possible that the comparison operator ==
returns false
although the pointers seem to be the same?
A few observations:
- The comparison returns
true
when both objects (a
andb
) live in the same crate. However, the comparison returnsfalse
when one of the objects (r
) was returned by the functionEngine::run
, which is defined in another crate. - The test correctly passes when I put the test function inside
lib.rs
. - The problem can be fixed by defining
struct Engine { intval: Object }
, but I'm still interested in the why.