#![no_std]
#![allow(unused_imports)]
use core::{
any::{Any, TypeId},
mem,
};
pub trait DowncastTrait {
unsafe fn convert_to_trait(&self, trait_id: TypeId) -> Option<&(dyn Any)>;
unsafe fn convert_to_trait_mut(&mut self, trait_id: TypeId) -> Option<&mut (dyn Any)>;
fn to_downcast_trait(&self) -> &dyn DowncastTrait;
fn to_downcast_trait_mut(&mut self) -> &mut dyn DowncastTrait;
}
#[macro_export]
macro_rules! downcast_trait {
( dyn $type:path, $src:expr) => {{
fn transmute_helper(src: &dyn DowncastTrait) -> Option<&dyn $type> {
unsafe {
src.convert_to_trait(TypeId::of::<dyn $type>())
.map(|dst| mem::transmute::<&(dyn Any), &(dyn $type)>(dst))
}
}
transmute_helper($src)
}};
}
#[macro_export]
macro_rules! downcast_trait_mut {
( dyn $type:path, $src:expr) => {{
fn transmute_helper(src: &mut dyn DowncastTrait) -> Option<&mut dyn $type> {
unsafe {
src.convert_to_trait_mut(TypeId::of::<dyn $type>())
.map(|dst| mem::transmute::<&mut (dyn Any), &mut (dyn $type)>(dst))
}
}
transmute_helper($src)
}};
}
#[macro_export]
macro_rules! downcast_trait_impl_convert_to
{
($(dyn $type:path),+) => {
unsafe fn convert_to_trait(& self, trait_id: TypeId) -> Option<& (dyn Any)> {
if false
{
None
}
$(
else if trait_id == TypeId::of::<dyn $type>()
{
Some(mem::transmute::<& (dyn $type), & dyn Any>(
self as & (dyn $type)
))
}
)*
else
{
None
}
}
unsafe fn convert_to_trait_mut(& mut self, trait_id: TypeId) -> Option<& mut (dyn Any)> {
if false
{
None
}
$(
else if trait_id == TypeId::of::<dyn $type>()
{
Some(mem::transmute::<& mut (dyn $type), & mut dyn Any>(
self as & mut (dyn $type)
))
}
)*
else
{
None
}
}
fn to_downcast_trait(& self) -> & dyn DowncastTrait
{
self
}
fn to_downcast_trait_mut(& mut self) -> & mut dyn DowncastTrait
{
self
}
};
}
#[cfg(test)]
mod tests {
use super::*;
trait Downcasted {
fn get_number(&self) -> u32;
}
trait Downcasted2 {
fn get_number(&self) -> u32;
}
struct Downcastable {
val: u32,
}
impl Downcasted for Downcastable {
fn get_number(&self) -> u32 {
self.val + 123
}
}
impl Downcasted2 for Downcastable {
fn get_number(&self) -> u32 {
self.val + 456
}
}
impl DowncastTrait for Downcastable {
downcast_trait_impl_convert_to!(dyn Downcasted, dyn Downcasted2);
}
#[test]
fn exploration() {
let mut tst = Downcastable { val: 0 };
let ts: &mut dyn DowncastTrait = tst.to_downcast_trait_mut();
let downcasted_maybe = downcast_trait!(dyn Downcasted, ts);
if let Some(downcasted) = downcasted_maybe {
assert_eq!(downcasted.get_number(), 123);
}
let downcasted_maybe2 = downcast_trait!(dyn Downcasted2, ts);
if let Some(downcasted2) = downcasted_maybe2 {
assert_eq!(downcasted2.get_number(), 456);
}
let mut downcasted_maybemut = downcast_trait_mut!(dyn Downcasted2, ts);
match &mut downcasted_maybemut {
Some(downcasted_mut) => {
assert_eq!(downcasted_mut.get_number(), 456);
}
None => assert!(false),
}
}
}