1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
//! Extended type erasure support.
//!
//! The `AnyTrait` trait provides dynamic upcasting to trait objects.

mod erased;
mod mut_any_unsized;
mod ref_any_unsized;
mod static_wrapper;
pub mod type_name;
mod type_name_id;

use crate::hkt::Marker;

pub use mut_any_unsized::*;
pub use ref_any_unsized::*;
pub use static_wrapper::*;
pub use type_name_id::*;

pub trait AnyTrait<'lt> {
    fn upcast_by_id(
        &self,
        id: WithLtTypeId<'lt>,
    ) -> Option<RefAnyUnsized<'_, 'lt>> {
        let _id = id;
        None
    }

    fn upcast_by_id_mut(
        &mut self,
        id: WithLtTypeId<'lt>,
    ) -> Option<MutAnyUnsized<'_, 'lt>> {
        let _id = id;
        None
    }
}

impl<'u, 'lt: 'u> dyn AnyTrait<'lt> + 'u {
    #[track_caller]
    pub fn upcast<'r, T: ?Sized + type_name::WithLt<'r, 'lt>>(&'r self) -> Option<&'r T> {
        self.upcast_by_id(WithLtTypeId::of::<T>())
            .map(|value| match value.downcast::<T>() {
                Ok(value) => value,
                Err(_) => panic!("wrong type returned by upcast_by_id"),
            })
    }

    #[track_caller]
    pub fn upcast_mut<'r, T: ?Sized + type_name::WithLt<'r, 'lt>>(
        &'r mut self,
    ) -> Option<&'r mut T> {
        self.upcast_by_id_mut(WithLtTypeId::of::<T>())
            .map(|value| match value.downcast::<T>() {
                Ok(value) => value,
                Err(_) => panic!("wrong type returned by upcast_by_id_mut"),
            })
    }
}

const _: () = {
    pub struct Ref<T: ?Sized>(Marker<T>);

    impl<'lt, 'ctx, T: ?Sized> type_name::Lower<'lt, 'ctx, &'lt &'ctx ()> for Ref<T>
    where
        T: type_name::Lower<'lt, 'ctx, &'lt &'ctx ()>,
    {
        type Lowered = &'lt type_name::Lowered<'lt, 'ctx, T>;
    }

    impl<'lt, 'ctx, T: ?Sized> type_name::Raise<'lt, 'ctx, &'lt &'ctx ()> for &'lt T
    where
        T: type_name::Raise<'lt, 'ctx, &'lt &'ctx ()>,
    {
        type Raised = Ref<type_name::Raised<'lt, 'ctx, T>>;
    }
};

const _: () = {
    pub struct Mut<T: ?Sized>(Marker<T>);

    impl<'lt, 'ctx, T: ?Sized> type_name::Lower<'lt, 'ctx, &'lt &'ctx ()> for Mut<T>
    where
        T: type_name::Lower<'lt, 'ctx, &'lt &'ctx ()>,
    {
        type Lowered = &'lt mut type_name::Lowered<'lt, 'ctx, T>;
    }

    impl<'lt, 'ctx, T: ?Sized> type_name::Raise<'lt, 'ctx, &'lt &'ctx ()> for &'lt mut T
    where
        T: type_name::Raise<'lt, 'ctx, &'lt &'ctx ()>,
    {
        type Raised = Mut<type_name::Raised<'lt, 'ctx, T>>;
    }
};

#[doc(hidden)]
#[macro_export]
macro_rules! trait_by_id {
    {
        &
        $this:ident,
        $id:ident,
        {
            type Impls = ($($trait:ty),* $(,)?);
        }
    } => {{
        match $id {
            $(
            $id if $id == $crate::any::WithLtTypeId::of::<$trait>() => {
                return Some($crate::any::RefAnyUnsized::new($this as &$trait))
            }
            )*
            _ => {}
        }
    }};
    {
        &mut
        $this:ident,
        $id:ident,
        {
            type Impls = ($($trait:ty),* $(,)?);
        }
    } => {{
        match $id {
            $(
            $id if {
                eprintln!("a: {:?}\nb: {:?}", &$id, $crate::any::WithLtTypeId::of::<$trait>());
                $id == $crate::any::WithLtTypeId::of::<$trait>()
            }=> {
                return Some($crate::any::MutAnyUnsized::new($this as &mut $trait))
            }
            )*
            _ => {}
        }
    }};
}
#[doc(inline)]
pub use trait_by_id;