Dyn Any changes TypeId?

I'm writing my own rust wrapper for the library GLFW. In this library the GLFWwindow type has the ability to store a pointer of type *mut c_void of any arbitrary user data.
I've decided that in my case this pointer should store a mutable reference to dyn Any.

pub fn set_data<T>(&self, data: &mut T)
where
     T: any::Any + 'static,
{
    let as_ref = data as &mut (dyn any::Any + 'static);
    dbg!(as_ref.type_id());
    let ptr = as_ref as *mut dyn any::Any;
    unsafe {
        // raw: NonNull<GLFWwindow>,
        glfw_rs_sys::glfwSetWindowUserPointer(self.raw.as_ptr(), ptr.cast());
    }
}

pub fn get_data<T>(&self) -> Option<&mut T>
where
      T: any::Any + 'static,
 {
     let ptr = unsafe { glfw_rs_sys::glfwGetWindowUserPointer(self.raw.as_ptr()) }
         as *mut dyn any::Any;
     let as_mut = unsafe { ptr.as_mut() };
     match as_mut {
         Some(reference) => {
             dbg!(reference.type_id());
             reference.downcast_mut()
         }
         None => None,
     }
}

Example usage:

llet mut user_data = 10.0_f64;
window.set_data(&mut user_data);
let got = window.get_data::<f64>();
println!("{got:?}");

But when you run this example, it prints this:

[glfw-test/src/window.rs:131:9] as_ref.type_id() = TypeId(0xc45c25bfe577a84e0b073a6684adcb7c)
[glfw-test/src/window.rs:147:17] reference.type_id() = TypeId(0xd8beda7b1917692422de15bb4429a07f)
None

Is this a bug or am I missing something?
Also I know that get_data shouldn't just return a mutable reference, this code is just a prototype currently

One pointer.

That's two pointers.

It wouldn't fit.

tysm!!

An interesting exercise, actually.

#[test]
fn dyn_ref() {
    let ref mut i = 42; // your data
    let i_dyn = i as &mut dyn std::any::Any;
    let type_id_before = i_dyn.type_id();
    
    let ptr_arr: [usize; 2] = unsafe { std::mem::transmute(i_dyn) };
    let boxed = Box::new(ptr_arr);
    let ptr = Box::into_raw(boxed);
    // ^ plain ptr, store as *mut c_void

    // .. later on, to reconstruct:
    let boxed = unsafe { *Box::from_raw(ptr) };
    let i_dyn: &mut dyn std::any::Any = unsafe { std::mem::transmute(boxed) };
    let type_id_after = i_dyn.type_id();

    assert_eq!(type_id_before, type_id_after);
}

Whether this actually makes any sense or not, is another point entirely.

1 Like

What's happening is that the type id you're seeing is that of c_void, as you're coercing c_void into dyn Any.

2 Likes