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?
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.
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.
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 )