2

In Rust, a &T where T is a trait is a fat reference, which actually corresponds to raw::TraitObject:

pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

Using TraitObject, one can de-construct and re-construct a &T at leisure.

However, while obtaining the vtable from de-constructing a &T is easy, what if I never have the &T in the first place, but just a T and S; essentially, something along the lines of:

fn make_vptr<T: ?Sized, S>() -> *mut ();

How could I divine the v-ptr from there? Is there any intrinsic I could use?

Note: the naive implementation of creating a S (or conjuring it from thin-air) and then making a &T reference does not work; the compiler complains that T is not necessarily a trait and therefore that &T is either one pointer or two pointers in size.

Josh Lee
  • 171,072
  • 38
  • 269
  • 275
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722

2 Answers2

3

A possibility is to use a macro to do the magic job:

#![feature(raw)]

macro_rules! make_vptr(
    ($S:ty, $T:ty) => ({
        let s: &$S = unsafe { ::std::mem::uninitialized() };
        let t: &$T = s;
        let r: ::std::raw::TraitObject = unsafe { ::std::mem::transmute(t) };
        r.vtable
    })
);

This code will not compile if T is not a trait (thanks to transmute(..) checking that &T is a fat pointer) or if T is not implemented by S (thanks to the assignment).

Then, it can be used directly:

use std::fmt::Display;

fn main() {
    let u32_display_vtable = make_vptr!(u32, Display);

    let x = 42u32;

    let disp: &Display = unsafe {
        ::std::mem::transmute(::std::raw::TraitObject {
            data: &x as *const _ as *mut _,
            vtable: u32_display_vtable,
        })
    };

    println!("{}", disp);
}
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Levans
  • 14,196
  • 3
  • 49
  • 53
  • Not as generic (unfortunately), as it cannot be called within a generic function, but it should be sufficient for my purpose. Thanks! – Matthieu M. May 17 '15 at 17:08
0

I don't believe this is currently possible.

In order for this to work, you'd need to be able to constrain the T generic parameter to only accept traits. You can't do this. As a result, it won't ever let you do anything with &T that depends on it being a trait, such as getting the vtable.

DK.
  • 55,277
  • 5
  • 189
  • 162