1#![feature(allocator_api)]
2#![feature(ptr_metadata)]
3
4#![no_std]
5
6#[doc=include_str!("../README.md")]
7type _DocTestReadme = ();
8
9extern crate alloc;
10
11use alloc::boxed::Box;
12use alloc::rc::Rc;
13use alloc::sync::Arc;
14use arraybox::ArrayBox;
15use downcast_rs::{Downcast, impl_downcast};
16use core::alloc::Allocator;
17use core::any::TypeId;
18use core::ops::Deref;
19use core::ptr::{self, DynMetadata, Pointee};
20
21#[doc(hidden)]
22pub use core::any::TypeId as core_any_TypeId;
23#[doc(hidden)]
24pub use core::option::Option as core_option_Option;
25
26pub type BoxedInterfaceMetadata =
28 ArrayBox<'static, dyn IsInterfaceMetadata, InterfaceMetadata<dyn IsInterfaceMetadata>>
29;
30
31pub trait IsInterfaceMetadata: Downcast { }
35
36impl_downcast!(IsInterfaceMetadata);
37
38pub struct InterfaceMetadata<DynInterface: ?Sized>(pub DynMetadata<DynInterface>);
42
43impl<DynInterface: ?Sized + 'static> IsInterfaceMetadata for InterfaceMetadata<DynInterface> { }
44
45pub unsafe trait SupportsInterfaces {
56 fn get_interface_metadata(&self, dyn_interface_id: TypeId) -> Option<BoxedInterfaceMetadata>;
57}
58
59pub fn dyn_cast_ref<T: SupportsInterfaces + ?Sized, DynInterface: ?Sized + 'static>(
61 x: &T
62) -> Option<&DynInterface> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
63 unsafe { dyn_cast_raw(x, |x| (x as *const T, ()), |x, ()| &*x) }
64}
65
66pub fn dyn_cast_mut<T: SupportsInterfaces + ?Sized, DynInterface: ?Sized + 'static>(
68 x: &mut T
69) -> Option<&mut DynInterface> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
70 unsafe { dyn_cast_raw_mut(x, |x| (x as *mut T, ()), |x, ()| &mut *x) }
71}
72
73pub fn dyn_cast_box<T: SupportsInterfaces + ?Sized, DynInterface: ?Sized + 'static, A: Allocator>(
75 x: Box<T, A>
76) -> Option<Box<DynInterface, A>> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
77 unsafe { dyn_cast_raw_mut(x, Box::into_raw_with_allocator, Box::from_raw_in) }
78}
79
80pub fn dyn_cast_rc<T: SupportsInterfaces + ?Sized, DynInterface: ?Sized + 'static>(
82 x: Rc<T>
83) -> Option<Rc<DynInterface>> where
84 DynInterface: Pointee<Metadata=DynMetadata<DynInterface>>,
85 T: Pointee<Metadata=DynMetadata<T>>
86{
87 unsafe { dyn_cast_raw(x, |x| (Rc::into_raw(x), ()), |x, ()| Rc::from_raw(x)) }
88}
89
90pub fn dyn_cast_arc<T: SupportsInterfaces + ?Sized, DynInterface: ?Sized + 'static>(
92 x: Arc<T>
93) -> Option<Arc<DynInterface>> where
94 DynInterface: Pointee<Metadata=DynMetadata<DynInterface>>,
95 T: Pointee<Metadata=DynMetadata<T>>
96{
97 unsafe { dyn_cast_raw(x, |x| (Arc::into_raw(x), ()), |x, ()| Arc::from_raw(x)) }
98}
99
100pub unsafe fn dyn_cast_raw_mut<
112 T: SupportsInterfaces + ?Sized,
113 DynInterface: ?Sized + 'static,
114 X: Deref<Target=T>,
115 Y,
116 A
117>(
118 x: X,
119 into_raw_parts: fn(X) -> (*mut T, A),
120 from_raw_parts: unsafe fn(*mut DynInterface, A) -> Y
121) -> Option<Y> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
122 let metadata = x.get_interface_metadata(TypeId::of::<DynInterface>())?;
123 let metadata = metadata.downcast_ref::<InterfaceMetadata<DynInterface>>()
124 .unwrap_or_else(|| panic!("invalid get_dyn_cast_metadata implementation"))
125 .0
126 ;
127 let (raw_ptr, a) = into_raw_parts(x);
128 let raw_ptr = raw_ptr.to_raw_parts().0;
129 let raw_ptr = ptr::from_raw_parts_mut(raw_ptr, metadata);
130 let x = from_raw_parts(raw_ptr, a);
131 Some(x)
132}
133
134pub unsafe fn dyn_cast_raw<
146 T: SupportsInterfaces + ?Sized,
147 DynInterface: ?Sized + 'static,
148 X: Deref<Target=T>,
149 Y,
150 A
151>(
152 x: X,
153 into_raw_parts: fn(X) -> (*const T, A),
154 from_raw_parts: unsafe fn(*const DynInterface, A) -> Y
155) -> Option<Y> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
156 let metadata = x.get_interface_metadata(TypeId::of::<DynInterface>())?;
157 let metadata = metadata.downcast_ref::<InterfaceMetadata<DynInterface>>()
158 .unwrap_or_else(|| panic!("invalid get_dyn_cast_metadata implementation"))
159 .0
160 ;
161 let (raw_ptr, a) = into_raw_parts(x);
162 let raw_ptr = raw_ptr.to_raw_parts().0;
163 let raw_ptr = ptr::from_raw_parts(raw_ptr, metadata);
164 let x = from_raw_parts(raw_ptr, a);
165 Some(x)
166}
167
168#[inline]
173pub fn try_get_interface_metadata_for<DynInterface: ?Sized + 'static>(
174 dyn_interface_id: TypeId,
175 this: &DynInterface,
176) -> Option<BoxedInterfaceMetadata> where DynInterface: Pointee<Metadata=DynMetadata<DynInterface>> {
177 if dyn_interface_id == TypeId::of::<DynInterface>() {
178 Some(ArrayBox::new(InterfaceMetadata(ptr::metadata(this as *const DynInterface))))
179 } else {
180 None
181 }
182}
183
184#[macro_export]
188macro_rules! impl_supports_interfaces {
189 (
190 $name:ident<$($gen_param:ident $(: $gen_bound:path)?),*> $(: $($($interface:path),+ $(,)?)?)?
191 ) => {
192 unsafe impl<$($gen_param $(: $gen_bound)?),*> $crate::SupportsInterfaces for $name<$($gen_param),*> {
193 fn get_interface_metadata(
194 &self,
195 dyn_interface_id: $crate::core_any_TypeId
196 ) -> $crate::core_option_Option<$crate::BoxedInterfaceMetadata> {
197 $($($(
198 if let $crate::core_option_Option::Some(metadata) =
199 $crate::try_get_interface_metadata_for::<dyn $interface>(
200 dyn_interface_id, self
201 )
202 {
203 return $crate::core_option_Option::Some(metadata);
204 }
205 )+)?)?
206 $crate::core_option_Option::None
207 }
208 }
209 };
210
211 (
212 $name:ty $(: $($($interface:path),+ $(,)?)?)?
213 ) => {
214 unsafe impl $crate::SupportsInterfaces for $name {
215 fn get_interface_metadata(
216 &self,
217 dyn_interface_id: $crate::core_any_TypeId
218 ) -> $crate::core_option_Option<$crate::BoxedInterfaceMetadata> {
219 $($($(
220 if
221 let $crate::core_option_Option::Some(metadata) =
222 $crate::try_get_interface_metadata_for::<dyn $interface>(
223 dyn_interface_id, self
224 )
225 {
226 return $crate::core_option_Option::Some(metadata);
227 }
228 )+)?)?
229 $crate::core_option_Option::None
230 }
231 }
232 };
233}