4

Is there a way to access the TypeId (std::any::TypeId::of::<T>) of a struct member by name?

If I have a basic struct:

MyStruct {
    value: i64,
}

And I only know MyStruct and value, is there a way to access TypeId::of::<i64> - where i64 depends on the type of value?

main () {
    assert_eq!(
        TypeId::of::<i64>,
        // ^^^ this works
        type_id_of!(MyStruct, value),
        // ^^^ this is what I'm looking for
    );
}

See related question: Is it possible to access the type of a struct member for function signatures or declarations?

Community
  • 1
  • 1
ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 1
    Maybe adding an example of how it would work can help. Would it be something like `TypeId::of::`? Note that this syntax does not exist, but I think it serves as an example of what you are trying to achieve – aochagavia Feb 08 '17 at 11:24
  • 1
    Added example to the question – ideasman42 Feb 08 '17 at 11:38

1 Answers1

7

You can use type detection to deduce the TypeId of any field of a value you have, as long as it's 'static (other TypeId::of doesn't work):

fn type_id<T: 'static + ?Sized>(_: &T) -> TypeId {
    TypeId::of::<T>()
}

fn main() {
    let m = MyStruct { value: 4 };
    println!("{:?} {:?}", TypeId::of::<i64>(), type_id(&m.value));
}

Then, leveraging the strategy in the offsetof question you asked, you can make a macro to get it from a type without having an instance:

macro_rules! type_id_of {
    ($t:ty, $f:ident) => {
        {
            fn type_of<T: 'static + ?Sized>(_: &T) -> TypeId {
                TypeId::of::<T>()
            }
            let base: $t = unsafe { ::std::mem::uninitialized() };
            let result = type_of(&base.$f);
            ::std::mem::forget(base);
            result
        }
    }
}

fn main() {
    println!("{:?} {:?}", TypeId::of::<i64>(), type_id_of!(MyStruct, value));
}
Community
  • 1
  • 1
Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • This is great! I didn't think it would be possible – aochagavia Feb 08 '17 at 11:34
  • 1
    @aochagavia: Once you know how to write `offset_of`, the rest is easy. It's not universal though because `TypeId::of` has this annoying restriction that `T` must be `'static` but I guess there's nothing *I* can do about that. – Matthieu M. Feb 08 '17 at 12:04