use std::any::TypeId;
pub enum Test {
A(i32),
B(u32),
C(f32),
}
impl Test {
pub fn get<T: 'static>(&self) -> Option<&T> {
// SAFETY: Using `TypeId` we know what type `T` is and whether we store
// a value of it in one of our variants. Therefore the reborrows of
// the casted pointers we use below to tell the compiler that we in
// fact return a `T` can be considered safe.
match (TypeId::of::<T>(), self) {
(id, Self::A(x)) if id == TypeId::of::<i32>() => {
Some(unsafe { &*(x as *const i32 as *const T) })
}
(id, Self::B(x)) if id == TypeId::of::<u32>() => {
Some(unsafe { &*(x as *const u32 as *const T) })
}
(id, Self::C(x)) if id == TypeId::of::<f32>() => {
Some(unsafe { &*(x as *const f32 as *const T) })
}
_ => None,
}
}
}
fn main() {
let a = Test::A(0);
let x = a.get::<i32>();
assert_eq!(x, Some(&0));
let y = a.get::<u32>();
assert_eq!(y, None);
let z = a.get::<f32>();
assert_eq!(z, None);
}
That way you always need to carry the T: VariantTypeOfTest bounds everywhere you use it, while the other implementations return None if it isn't a variant. The only way i could think of to get around this is with specialisation and providing a default None return for every T