I have a trait function that I can't control that looks roughly like
fn do_something_with_s<S>(&self, s: S) where S: Trait;
I want to implement this as
fn do_something_with_s<S>(&self, s: S) where S: Trait {
if let Some(my_custom_type) = as_my_custom_type(&s) {
my_custom_type.do_specialized_thing()
} else {
s.do_trait_thing()
}
}
How can I implement as_my_custom_type?
fn as_my_custom_type<S>(s: &S) -> Option<&MyCustomType> {
todo!()
}
I was hoping to use something in std::any to make this work, like
fn as_my_custom_type(s: &dyn std::any::Any) -> Option<&MyCustomType> {
s.downcast_ref::<MyCustomType>()
}
or
fn as_my_custom_type(s: &S) -> Option<&MyCustomType> {
if std::any::TypeId::of::<S>() == std::any::TypeId::of::<MyCustomType>() {
let mine = unsafe { std::mem::transmute::<&S, &MyCustomType>() };
Some(mine)
} else {
None
}
}
but Any and TypeId require the type parameter to be 'static and the trait I don't control does not make that guarantee.
Certainly the compiler knows the type of S; is there any way I can get it to tell me if that S is MyCustomType in specific?
Right now, I'm doing a huge hack and I don't like it, because it's not guaranteed that it will work.
#[repr(C)]
struct MyCustomType {
magic: usize,
}
impl MyCustomType {
const MAGIC: usize = 0x0123456789abcdef;
}
impl Default for MyCustomType {
fn default() -> Self {
Self { magic: Self::MAGIC }
}
}
fn as_my_custom_type(s: &S) -> Option<&MyCustomType> {
if std::mem::size_of::<S>() == std::mem::size_of::<MyCustomType>() {
let mine = unsafe { std::mem::transmute::<&S, &MyCustomType>() };
if mine.magic == MyCustomType::MAGIC {
Some(mine)
} else {
None
}
} else {
None
}
}