How to compare trait objects when user-defined types wrap

โš“ Rust    ๐Ÿ“… 2025-09-08    ๐Ÿ‘ค surdeus    ๐Ÿ‘๏ธ 2      

surdeus

Iโ€™m working on a library where I need to compare if two wrapped trait objects actually point to the same underlying value.

The tricky part is that users of the library can supply their own types (e.g. Qux) that embed library types (like Bar) while implementing the same traits.

Hereโ€™s a reduced example:

use std::any::{Any};
use std::sync::{Arc, Mutex};

// types provided by the Library
pub trait IFoo: Any + Send + Sync {}
pub struct Foo {}
impl dyn IFoo {
    pub fn as_any(&self) -> &dyn Any {
        self
    }
}
impl IFoo for Foo {}

pub trait IBar: Any + Send + Sync {}
pub struct Bar {}
impl dyn IBar {
    pub fn as_any(&self) -> &dyn Any {
        self
    }
}
impl IBar for Bar {}

// Types from User of the Library (although defined in here to keep things simple)
struct Qux {
    bar: Bar, // to forward invocations
}
impl IBar for Qux {}

// Library
pub struct Comparator {
    left: Arc<dyn Any + Send + Sync>,
}

impl Comparator {
    pub fn compare(&self, right: &Arc<dyn Any + Send + Sync>) -> bool {
        if (*self.left).type_id() != (**right).type_id() {
            return false;
        }

        // Compare underlying pointers
        let left_ptr = Arc::as_ptr(&self.left) as *const ();
        let right_ptr = Arc::as_ptr(right) as *const ();
        left_ptr == right_ptr
    }
}

fn main() {
       let foo: Arc<dyn IFoo> = Arc::new(Foo {});
    let foo_any: Arc<dyn Any + Send + Sync> = Arc::new(foo.clone());
    let foo_any2: Arc<dyn Any + Send + Sync> = Arc::new(foo.clone());

    let comparator = Comparator { left: foo_any.clone() };
    println!("Compare foo -> foo: {}", comparator.compare(&foo_any)); // true
    println!("Compare foo -> foo2: {}", comparator.compare(&foo_any2)); 

    let bar: Arc<Mutex<dyn IBar>> = Arc::new(Mutex::new(Bar {}));
    let bar_any: Arc<dyn Any + Send + Sync> = Arc::new(bar.clone());
    let bar_any2: Arc<dyn Any + Send + Sync> = Arc::new(bar.clone());

    let comparator = Comparator { left: bar_any.clone() };
    println!("Compare bar -> bar: {}", comparator.compare(&bar_any)); // true
    println!("Compare bar -> bar2: {}", comparator.compare(&bar_any2));

    let qux: Arc<Mutex<dyn IBar>> = Arc::new(Mutex::new(Qux { bar: Bar {} }));
    let qux_any: Arc<dyn Any + Send + Sync> = Arc::new(qux.clone());

    let comparator = Comparator { left: qux_any.clone() };
    println!("Compare qux -> qux: {}", comparator.compare(&qux_any)); // true
    
    let qux_any2: Arc<dyn Any + Send + Sync> = Arc::new(qux.clone());
    println!("Compare qux -> qux2: {}", comparator.compare(&qux_any2));
}

Standard Output

Compare foo -> foo: true
Compare foo -> foo2: false
Compare bar -> bar: true
Compare bar -> bar2: false
Compare qux -> qux: true
Compare qux -> qux2: false

Expectation should return true for all comparisons

Playground: Rust Playground

10 posts - 3 participants

Read full topic

๐Ÿท๏ธ Rust_feed