rustmetadataraw-pointer

What does Raw pointer metadata mean in Rust?


I wonder why the metadata of the raw pointer in box is (), but the metadata of sized, which is stored on the stack, is the metadata of a slice ([T]), which is described as the number of items and has the type usize in Pointees documentation.

I have read the explanation on Pointee, and wrote the following code:

#![feature(box_as_ptr)]
#![feature(ptr_metadata)]
#![allow(unused)]
struct MySuperSliceable<T: ?Sized> {
    info: u32,
    data: T,
}

fn main() {
    let sized: MySuperSliceable<[u8; 8]> = MySuperSliceable {
        info: 17,
        data: [0; 8],
    };
    let box_sized = Box::new(MySuperSliceable {
        info: 18,
        data: [0; 12],
    });
    
    let dynamic: &MySuperSliceable<[u8]> = &sized;
    let box_dynamic = Box::as_ptr(&box_sized);

    assert_eq!(std::ptr::metadata(dynamic), 8_usize);
    assert_eq!(std::ptr::metadata("hello, world!"), 13_usize);
    let a = 10;
    assert_eq!(std::ptr::metadata(&a), ());
    
    assert_eq!(std::ptr::metadata(box_dynamic), ());
    assert_eq!(std::ptr::metadata(box_sized.as_ref()), ());
}

Playground

I think these assertions

assert_eq!(std::ptr::metadata(box_dynamic), ());
assert_eq!(std::ptr::metadata(box_sized.as_ref()), ());

should be

assert_eq!(std::ptr::metadata(box_dynamic), 12_usize);
assert_eq!(std::ptr::metadata(box_sized.as_ref()), 12_usize);

but it is wrong.

Moreover, I would appreciate it if someone could write an extra example to explain the metadata of DST (Dynamically Sized Types), I also confused about it.


Solution

  • Your problem is that you made assumptions about what the types of your variables and expressions are, but your assumptions are wrong, box_dynamic despite it's name is not a DST nor does it point to one, it's a *const MySuperSliceable<[i32; 12]>, which is a pointer to a statically sized type and hence a thin pointer, without metadata.

    The same is true for box_sized.as_ref() which you again assume to return a pointer to a DST, but it returns a &MySuperSliceable<[i32; 12]>, similarly to above, the size of an array is statically known and so this is a thin pointer, too.

    the metadata of sized, which is stored on the stack, is the metadata of a slice ([T])

    How do you get to that conclusion? sized is not a pointer, so it can't even have (pointer-)metadata. Maybe you're referring to the metadata that dynamic carries, but despite sized being of statically known size, dynamic is a pointer, that points to a MySuperSliceable<[i32]>, which is a DST. The compiler is able to convert these pointers between each other and adds the corresponding metadata where applicable, the mechanism by which it happens here is called unsized coersion and happens because you assign &sized to an explicitly typed variable let dynamic: &MySuperSliceable<[u8]> where the type is a DST. What memory the variables are stored in and thus where the pointer points to, be it heap, stack, static memory, …, does not play a role on whether a pointer is eligible for unsized coercion.