Conversion from generic type to concrete type


#1

I have a function whose input is generic over a type which is bounded by various traits. Meanwhile, I have an enum whose values are concrete types which implement the traits constraining the generic type mentioned above. I want to return the enum from the function, but when I pattern match against the input and try and construct the concrete type, I get something like:

expected struct Group, found type parameter

Can a trait object or generic be cast to a concrete type? Is there a way to do this in unsafe rust if not safe rust?


#2

Hi, that description is quite complex, can you please post example code? (preferably through https://play.rust-lang.org?)


#3

I encountered a similar issue and built value_from_type_{macros|traits}. It contains a procedural macro which can be used on nightly to convert from types to enum values. See https://crates.io/crates/value_from_type_macros

The procedural macro must be used as an attribute onto a module defining some structs. The macro will then build the enum and custom IntoEnum +FromType implementations.

#![feature(proc_macro)]
extern crate value_from_type_macros;
extern crate value_from_type_traits;

// Attribute macro must be imported through a use statement.
use value_from_type_macros::value_from_type;
// Implemented trait on `EnumName`
use value_from_type_traits::IntoEnum;

mod temp {
    // The parameter indicates the enum identifier.
    #![value_from_type(EnumName)]

    #[derive(Debug)]
    pub struct X(); 
}

// Explicit import for sake of example.
// Notice: EnumName::X IS the enum variant corresponding to the struct temp::X!
use self::temp::{EnumName, X};
// use self::temp::*;

fn main() {
	assert_eq!(EnumName::X, X::into_enum()); 
}

And within functions code would look like this

fn do_thing<X: IntoEnum<EnumName>>() {
    let enum_value = X::into_enum();
}

It looks like your use case is a bit more complex, but this is may be a good start.


#4

Some trait objects support dynamic downcasting (eg Box<Any>) but you can’t downcast a generic parameter - after all, the caller is providing a concrete type. I’d avoid unsafe code for this purpose.

The IntoEnum solution that @Bert-Proesmans suggested is a good one. Alternatively, if possible, make your enum generic or make the input an enum rather than a generic parameter.


#5

That is a good idea. I will give this a shot, although I actually solved my problem by more radical design changes which i wont bore everyone with. However, this problem led me to wonder more generally about how to do this.

I even tried using unsafe std::mem::transmute, but the compiler complained that the generic didn’t have a fixed size. It still seems like you should be able to force the issue in unsafe if you know what you are doing (which I most certainly do not). Since I derived Debug when i print it out appropriately, I can see that they are equivalent…

I was going to rewrite my enum to be generic, but that enum gets wrapped by another enum (this is a TUI which uses enums as messages between view and controller), but the thought of having to litter the code with generics and type constraints to support one value made me a bit depressed. ( which i suspect is a common side effect of Rust in some cases :slight_smile: )


#6

You can try transmute_copy. However, needless to say, this is a very sharp tool and should be avoided as much as possible.