How can I use Any to compare type-erased object?

For complicated reasons, I need to create type-erased versions of some objects, that implement a non-object-safe trait.

A simplified version of my type looks like:

pub trait AnyState: Any {
    fn dyn_clone(&self) -> Box<dyn AnyState>;
    fn dyn_eq(&self, other: &Box<dyn AnyState>) -> bool;
}

impl<T> AnyState for T
where
    T: Clone + PartialEq + 'static,
{
    fn dyn_clone(&self) -> Box<dyn AnyState> {
        let b = Box::new(self.clone());
    }

    fn dyn_eq(&self, other: &Box<dyn AnyState>) -> bool {
        if let Some(other) = Any::downcast_ref::<Self>(other) {
            other.eq(self)
        } else {
            false
        }
    }
}

pub struct AnyStateBox {
    value: Box<dyn AnyState>,
}

impl AnyStateBox {
    pub fn new(state: impl AnyState) -> Self {
        AnyStateBox {
            value: Box::new(state),
        }
    }
}

impl Clone for AnyStateBox {
    fn clone(&self) -> Self {
        AnyStateBox {
            value: self.value.dyn_clone(),
        }
    }
}


impl PartialEq for AnyStateBox {
    fn eq(&self, other: &Self) -> bool {
        self.value.dyn_eq(&other.value)
    }
}

But then, if I run

let state1 = AnyStateBox::new(42);
let state2 = state1.clone();

assert_eq!(state1, state2);

The test immediately fails; after some searching it turns out that the TypeId of the clone is different from the TypeId of the original, even though they're both i32.

Is there a way to fix this? I really need the type erasure for my design.

Can you please post a bit more complete code? When trying to reproduce your problem, I ran into these problems:

  1. The dyn_clone method is incomplete.
  2. The import of Any is missing.
  3. The assert calls fail because AnyStateBox doesn't implement Debug.

I stopped trying to reproduce your issue when I found out that I would have to write a manual Debug impl to get past the third problem. I assume you have a version of the code that fixes the above issues. Please post it.

After fixing the compiler errors @alice mentioned, I noticed that you are calling the wrong downcast_ref() function. You are calling it on a Box but you actually want the inner value; the Box will never be the same type as Self. Accordingly, this passes the assertion.

2 Likes

Yeah, I think this is it.

(funny thing, I actually noticed the same thing 10 minutes ago, but I couldn't get my as_any() method to compile; so thanks for your solution)

It works like a charm now. Thanks!

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.