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
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
use crate::Kind;
use core::{
    any::{Any, TypeId},
    fmt::{self, Display, Formatter},
};
use thiserror::Error;

pub type MethodIndex = u8;

pub struct MethodTypes {
    pub arguments: Vec<TypeId>,
    pub output: TypeId,
    pub receiver: Receiver,
}

#[derive(Debug, Error)]
pub enum CallError {
    #[error("invalid type for argument {0}")]
    Type(u8),
    #[error("{0}")]
    ArgumentCount(#[source] ArgumentCountError),
    #[error("{0}")]
    OutOfRange(#[source] OutOfRangeError),
    #[error("expected {0} receiver")]
    IncorrectReceiver(Receiver),
}

#[derive(Debug, Error)]
#[error("method {index} out of range")]
pub struct OutOfRangeError {
    pub index: MethodIndex,
}

#[derive(Debug, Error)]
#[error("got {got} arguments, expected {expected}")]
pub struct ArgumentCountError {
    pub expected: usize,
    pub got: usize,
}

#[derive(Debug, Error)]
#[error("no method with name {name}")]
pub struct NameError {
    pub name: String,
}

#[derive(Debug, Error)]
#[error("cannot cast to {target:?} in this context")]
pub struct CastError {
    pub target: TypeId,
}

/// A trait object that has reflection data generated by `#[object]`
///
/// This trait should not be implemented manually by any third-party crate. Trait objects of traits annotated
/// with `#[object]` will be marked with this trait to indicate their usability as reflected trait objects.
/// Moreover, any type that implements `Trait<dyn SomeTrait>` where `dyn SomeTrait: Reflected` will
/// have a generated implementation allowing it to satisfy `SomeTrait`.
pub trait Reflected: 'static {
    #[doc(hidden)]
    type Shim: Kind;
    #[doc(hidden)]
    type ErasedShim: From<Box<Self>>;
    #[doc(hidden)]
    const DO_NOT_IMPLEMENT_THIS_MARKER_TRAIT_MANUALLY: ();
}

#[derive(Debug)]
pub enum Receiver {
    Mutable,
    Immutable,
    Owned,
}

impl Display for Receiver {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        use Receiver::{Immutable, Mutable, Owned};

        write!(
            f,
            "{}",
            match self {
                Immutable => "an immutable",
                Mutable => "a mutable",
                Owned => "an owned",
            }
        )
    }
}

impl Receiver {
    pub fn is_mutable(&self) -> bool {
        use Receiver::Mutable;
        if let Mutable = self {
            true
        } else {
            false
        }
    }
}

pub enum SomeTrait {}

impl Reflected for SomeTrait {
    type Shim = ();
    type ErasedShim = ();
    const DO_NOT_IMPLEMENT_THIS_MARKER_TRAIT_MANUALLY: () = ();
}

impl From<Box<SomeTrait>> for () {
    fn from(_: Box<SomeTrait>) {}
}

pub trait Erased: Send + Trait<SomeTrait> {
    fn cast(self: Box<Self>, ty: TypeId) -> Result<Box<dyn Any + Send + Sync>, CastError>;
}

pub trait Cast<T: ?Sized + Reflected> {
    fn downcast(self) -> Result<Box<T>, CastError>;
    fn upcast(self) -> Result<Box<T>, CastError>;
}

impl<S: ?Sized + Reflected> Cast<S> for Box<dyn Erased> {
    fn downcast(self) -> Result<Box<S>, CastError> {
        self.cast(TypeId::of::<S>()).map(|erased| {
            *Box::<dyn Any>::downcast::<Box<S>>(erased)
                .map_err(|_| panic!("could not downcast after successful reinterpretation"))
                .unwrap()
        })
    }
    fn upcast(self) -> Result<Box<S>, CastError> {
        Trait::<SomeTrait>::upcast_erased(self, TypeId::of::<S>()).map(|erased| {
            erased
                .downcast()
                .expect("could not downcast after successful upcast")
        })
    }
}

impl<T: ?Sized + Reflected + Trait<T>, S: ?Sized + Reflected> Cast<S> for Box<T> {
    fn downcast(self) -> Result<Box<S>, CastError> {
        self.erase().cast(TypeId::of::<S>()).map(|erased| {
            *Box::<dyn Any>::downcast::<Box<S>>(erased)
                .map_err(|_| panic!("could not downcast after successful reinterpretation"))
                .unwrap()
        })
    }
    fn upcast(self) -> Result<Box<S>, CastError> {
        Trait::<T>::upcast_erased(self, TypeId::of::<S>()).map(|erased| {
            erased
                .downcast()
                .expect("could not downcast after successful upcast")
        })
    }
}

pub trait Trait<T: Reflected + ?Sized>: Sync + Send {
    fn call(
        &self,
        index: MethodIndex,
        args: Vec<Box<dyn Any + Send + Sync>>,
    ) -> Result<Box<dyn Any + Send + Sync>, CallError>;
    fn call_mut(
        &mut self,
        index: MethodIndex,
        args: Vec<Box<dyn Any + Send + Sync>>,
    ) -> Result<Box<dyn Any + Send + Sync>, CallError>;
    fn call_move(
        self: Box<Self>,
        index: MethodIndex,
        args: Vec<Box<dyn Any + Send + Sync>>,
    ) -> Result<Box<dyn Any + Send + Sync>, CallError>;
    fn by_name(&self, name: &'_ str) -> Result<MethodIndex, NameError>;
    fn count(&self) -> MethodIndex;
    fn name_of(&self, index: MethodIndex) -> Result<String, OutOfRangeError>;
    fn this(&self) -> TypeId;
    fn name(&self) -> String;
    fn types(&self, index: MethodIndex) -> Result<MethodTypes, OutOfRangeError>;
    /// Returns all supertraits in the form `TypeId::of<dyn SomeTrait>` for each supertrait `SomeTrait`.
    fn supertraits(&self) -> Vec<TypeId>;
    /// For a `TypeId` that is `TypeId::of<dyn SomeTrait>` returns the erasure of a concrete type
    /// `Box<dyn SomeTrait>` which can then be downcasted into.
    fn upcast_erased(self: Box<Self>, ty: TypeId) -> Result<Box<dyn Erased>, CastError>;
    fn erase(self: Box<Self>) -> Box<dyn Erased>;
}