| 1 | #![cfg_attr (not(feature = "std" ), no_std)] |
| 2 | |
| 3 | #[cfg (not(feature = "std" ))] |
| 4 | mod std { |
| 5 | pub use core::*; |
| 6 | } |
| 7 | |
| 8 | use std::any::{Any as StdAny, TypeId, type_name}; |
| 9 | use std::fmt::{self, Debug, Display}; |
| 10 | |
| 11 | #[cfg (feature = "std" )] |
| 12 | use std::{error::Error, rc::Rc, sync::Arc}; |
| 13 | |
| 14 | // ++++++++++++++++++++ Any ++++++++++++++++++++ |
| 15 | |
| 16 | pub trait Any: StdAny { |
| 17 | #[doc (hidden)] |
| 18 | fn as_any(&self) -> &dyn StdAny; |
| 19 | |
| 20 | #[doc (hidden)] |
| 21 | fn as_any_mut(&mut self) -> &mut dyn StdAny; |
| 22 | |
| 23 | #[doc (hidden)] |
| 24 | #[cfg (feature = "std" )] |
| 25 | fn into_any(self: Box<Self>) -> Box<dyn StdAny>; |
| 26 | |
| 27 | #[doc (hidden)] |
| 28 | #[cfg (feature = "std" )] |
| 29 | fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny>; |
| 30 | |
| 31 | fn type_name(&self) -> &'static str; |
| 32 | } |
| 33 | |
| 34 | impl<T> Any for T where T: StdAny { |
| 35 | #[doc (hidden)] |
| 36 | fn as_any(&self) -> &dyn StdAny { self } |
| 37 | |
| 38 | #[doc (hidden)] |
| 39 | fn as_any_mut(&mut self) -> &mut dyn StdAny { self } |
| 40 | |
| 41 | #[cfg (feature = "std" )] |
| 42 | fn into_any(self: Box<Self>) -> Box<dyn StdAny> { self } |
| 43 | |
| 44 | #[cfg (feature = "std" )] |
| 45 | fn into_any_rc(self: Rc<Self>) -> Rc<dyn StdAny> { self } |
| 46 | |
| 47 | fn type_name(&self) -> &'static str { type_name::<Self>() } |
| 48 | } |
| 49 | |
| 50 | #[cfg (feature = "std" )] |
| 51 | pub trait AnySync: Any + Send + Sync { |
| 52 | fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync>; |
| 53 | } |
| 54 | |
| 55 | #[cfg (feature = "std" )] |
| 56 | impl<T> AnySync for T where T: Any + Send + Sync { |
| 57 | fn into_any_arc(self: Arc<Self>) -> Arc<dyn StdAny + Send + Sync> { self } |
| 58 | } |
| 59 | |
| 60 | // ++++++++++++++++++++ TypeMismatch ++++++++++++++++++++ |
| 61 | |
| 62 | #[derive(Debug, Clone, Copy)] |
| 63 | pub struct TypeMismatch { |
| 64 | pub expected: &'static str, |
| 65 | pub found: &'static str, |
| 66 | } |
| 67 | |
| 68 | impl TypeMismatch { |
| 69 | pub fn new<T, O>(found_obj: &O) -> Self |
| 70 | where T: Any + ?Sized, O: Any + ?Sized |
| 71 | { |
| 72 | TypeMismatch { |
| 73 | expected: type_name::<T>(), |
| 74 | found: found_obj.type_name(), |
| 75 | } |
| 76 | } |
| 77 | } |
| 78 | |
| 79 | impl Display for TypeMismatch { |
| 80 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 81 | write!(fmt, "Type mismatch: Expected '{}', found '{}'!" , self.expected, self.found) |
| 82 | } |
| 83 | } |
| 84 | |
| 85 | #[cfg (feature = "std" )] |
| 86 | impl Error for TypeMismatch {} |
| 87 | |
| 88 | // ++++++++++++++++++++ DowncastError ++++++++++++++++++++ |
| 89 | |
| 90 | pub struct DowncastError<O> { |
| 91 | mismatch: TypeMismatch, |
| 92 | object: O, |
| 93 | } |
| 94 | |
| 95 | impl<O> DowncastError<O> { |
| 96 | pub fn new(mismatch: TypeMismatch, object: O) -> Self { |
| 97 | Self{ mismatch, object } |
| 98 | } |
| 99 | pub fn type_mismatch(&self) -> TypeMismatch { self.mismatch } |
| 100 | pub fn into_object(self) -> O { self.object } |
| 101 | } |
| 102 | |
| 103 | impl<O> Debug for DowncastError<O> { |
| 104 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 105 | fmt.debug_struct("DowncastError" ) |
| 106 | .field("mismatch" , &self.mismatch) |
| 107 | .finish() |
| 108 | } |
| 109 | } |
| 110 | |
| 111 | impl<O> Display for DowncastError<O> { |
| 112 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { |
| 113 | Display::fmt(&self.mismatch, fmt) |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | #[cfg (feature = "std" )] |
| 118 | impl<O> Error for DowncastError<O> {} |
| 119 | |
| 120 | // ++++++++++++++++++++ Downcast ++++++++++++++++++++ |
| 121 | |
| 122 | pub trait Downcast<T>: Any |
| 123 | where T: Any |
| 124 | { |
| 125 | fn is_type(&self) -> bool { self.type_id() == TypeId::of::<T>() } |
| 126 | |
| 127 | fn downcast_ref(&self) -> Result<&T, TypeMismatch> { |
| 128 | if self.is_type() { |
| 129 | Ok(self.as_any().downcast_ref().unwrap()) |
| 130 | } else { |
| 131 | Err(TypeMismatch::new::<T, Self>(self)) |
| 132 | } |
| 133 | } |
| 134 | |
| 135 | fn downcast_mut(&mut self) -> Result<&mut T, TypeMismatch> { |
| 136 | if self.is_type() { |
| 137 | Ok(self.as_any_mut().downcast_mut().unwrap()) |
| 138 | } else { |
| 139 | Err(TypeMismatch::new::<T, Self>(self)) |
| 140 | } |
| 141 | } |
| 142 | |
| 143 | #[cfg (feature = "std" )] |
| 144 | fn downcast(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<Self>>> { |
| 145 | if self.is_type() { |
| 146 | Ok(self.into_any().downcast().unwrap()) |
| 147 | } else { |
| 148 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
| 149 | Err(DowncastError::new(mismatch, self)) |
| 150 | } |
| 151 | } |
| 152 | |
| 153 | #[cfg (feature = "std" )] |
| 154 | fn downcast_rc(self: Rc<Self>) -> Result<Rc<T>, DowncastError<Rc<Self>>> { |
| 155 | if self.is_type() { |
| 156 | Ok(self.into_any_rc().downcast().unwrap()) |
| 157 | } else { |
| 158 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
| 159 | Err(DowncastError::new(mismatch, self)) |
| 160 | } |
| 161 | } |
| 162 | } |
| 163 | |
| 164 | #[cfg (feature = "std" )] |
| 165 | pub trait DowncastSync<T>: Downcast<T> + AnySync |
| 166 | where T: AnySync |
| 167 | { |
| 168 | fn downcast_arc(self: Arc<Self>) -> Result<Arc<T>, DowncastError<Arc<Self>>> { |
| 169 | if self.is_type() { |
| 170 | Ok(self.into_any_arc().downcast().unwrap()) |
| 171 | } else { |
| 172 | let mismatch = TypeMismatch::new::<T, Self>(&*self); |
| 173 | Err(DowncastError::new(mismatch, self)) |
| 174 | } |
| 175 | } |
| 176 | } |
| 177 | |
| 178 | // ++++++++++++++++++++ macros ++++++++++++++++++++ |
| 179 | |
| 180 | #[doc (hidden)] |
| 181 | pub mod _std { |
| 182 | #[cfg (feature = "std" )] |
| 183 | pub use std::*; |
| 184 | #[cfg (not(feature = "std" ))] |
| 185 | pub use core::*; |
| 186 | } |
| 187 | |
| 188 | /// Implements [`Downcast`](trait.Downcast.html) for your trait-object-type. |
| 189 | /// |
| 190 | /// ```ignore |
| 191 | /// impl_downcast!(Foo); |
| 192 | /// impl_downcast!(<B> Foo<B> where B: Bar); |
| 193 | /// impl_downcast!(<B> Foo<Bar = B>); |
| 194 | /// ``` |
| 195 | /// |
| 196 | /// expands to |
| 197 | /// |
| 198 | /// ```ignore |
| 199 | /// impl<T> Downcast<T> for Foo |
| 200 | /// where T: Any |
| 201 | /// {} |
| 202 | /// |
| 203 | /// impl<T, B> Downcast<T> for Foo<B> |
| 204 | /// where T: Any, B: Bar |
| 205 | /// {} |
| 206 | /// |
| 207 | /// impl<T, B> Downcast<T> for Foo<Bar = B> |
| 208 | /// where T: Any |
| 209 | /// {} |
| 210 | /// ``` |
| 211 | #[macro_export ] |
| 212 | macro_rules! impl_downcast { |
| 213 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
| 214 | impl<_T, $($params),+> $crate::Downcast<_T> for $base |
| 215 | where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)* |
| 216 | {} |
| 217 | }; |
| 218 | ($base:ty) => { |
| 219 | impl<_T> $crate::Downcast<_T> for $base |
| 220 | where _T: $crate::Any |
| 221 | {} |
| 222 | }; |
| 223 | } |
| 224 | |
| 225 | /// Implements [`Downcast`](trait.Downcast.html) and [`DowncastSync`](trait.DowncastSync.html) for your trait-object-type. |
| 226 | #[cfg (feature = "std" )] |
| 227 | #[macro_export ] |
| 228 | macro_rules! impl_downcast_sync { |
| 229 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
| 230 | impl<_T, $($params),+> $crate::Downcast<_T> for $base |
| 231 | where _T: $crate::Any, $($params: 'static,)* $($($bounds)+)* |
| 232 | {} |
| 233 | |
| 234 | impl<_T, $($params),+> $crate::DowncastSync<_T> for $base |
| 235 | where _T: $crate::AnySync, $($params: 'static,)* $($($bounds)+)* |
| 236 | {} |
| 237 | }; |
| 238 | ($base:ty) => { |
| 239 | impl<_T> $crate::Downcast<_T> for $base |
| 240 | where _T: $crate::Any |
| 241 | {} |
| 242 | |
| 243 | impl<_T> $crate::DowncastSync<_T> for $base |
| 244 | where _T: $crate::AnySync |
| 245 | {} |
| 246 | }; |
| 247 | } |
| 248 | |
| 249 | #[doc (hidden)] |
| 250 | #[macro_export ] |
| 251 | macro_rules! downcast_methods_core { |
| 252 | (@items) => { |
| 253 | #[allow(unused, missing_docs)] |
| 254 | pub fn is<_T>(&self) -> bool |
| 255 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
| 256 | { |
| 257 | $crate::Downcast::<_T>::is_type(self) |
| 258 | } |
| 259 | |
| 260 | #[allow(unused, missing_docs)] |
| 261 | pub fn downcast_ref<_T>(&self) -> $crate::_std::result::Result<&_T, $crate::TypeMismatch> |
| 262 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
| 263 | { |
| 264 | $crate::Downcast::<_T>::downcast_ref(self) |
| 265 | } |
| 266 | |
| 267 | #[allow(unused, missing_docs)] |
| 268 | pub fn downcast_mut<_T>(&mut self) -> $crate::_std::result::Result<&mut _T, $crate::TypeMismatch> |
| 269 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
| 270 | { |
| 271 | $crate::Downcast::<_T>::downcast_mut(self) |
| 272 | } |
| 273 | }; |
| 274 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
| 275 | impl<$($params),+> $base |
| 276 | where $($params: 'static,)* $($($bounds)+)* |
| 277 | { |
| 278 | $crate::downcast_methods_core!(@items); |
| 279 | } |
| 280 | }; |
| 281 | ($base:ty) => { |
| 282 | impl $base { |
| 283 | $crate::downcast_methods_core!(@items); |
| 284 | } |
| 285 | }; |
| 286 | } |
| 287 | |
| 288 | #[doc (hidden)] |
| 289 | #[macro_export ] |
| 290 | macro_rules! downcast_methods_std { |
| 291 | (@items) => { |
| 292 | $crate::downcast_methods_core!(@items); |
| 293 | |
| 294 | #[allow(unused, missing_docs)] |
| 295 | pub fn downcast<_T>(self: $crate::_std::boxed::Box<Self>) -> $crate::_std::result::Result<$crate::_std::boxed::Box<_T>, $crate::DowncastError<$crate::_std::boxed::Box<Self>>> |
| 296 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
| 297 | { |
| 298 | $crate::Downcast::<_T>::downcast(self) |
| 299 | } |
| 300 | |
| 301 | #[allow(unused, missing_docs)] |
| 302 | pub fn downcast_rc<_T>(self: $crate::_std::rc::Rc<Self>) -> $crate::_std::result::Result<$crate::_std::rc::Rc<_T>, $crate::DowncastError<$crate::_std::rc::Rc<Self>>> |
| 303 | where _T: $crate::Any, Self: $crate::Downcast<_T> |
| 304 | { |
| 305 | $crate::Downcast::<_T>::downcast_rc(self) |
| 306 | } |
| 307 | }; |
| 308 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
| 309 | impl<$($params),+> $base |
| 310 | $(where $($bounds)+)* |
| 311 | { |
| 312 | $crate::downcast_methods_std!(@items); |
| 313 | } |
| 314 | }; |
| 315 | ($base:ty) => { |
| 316 | impl $base { |
| 317 | $crate::downcast_methods_std!(@items); |
| 318 | } |
| 319 | }; |
| 320 | } |
| 321 | |
| 322 | #[doc (hidden)] |
| 323 | #[cfg (feature = "std" )] |
| 324 | #[macro_export ] |
| 325 | macro_rules! downcast_sync_methods { |
| 326 | (@items) => { |
| 327 | $crate::downcast_methods_std!(@items); |
| 328 | |
| 329 | #[allow(unused, missing_docs)] |
| 330 | pub fn downcast_arc<_T>(self: $crate::_std::sync::Arc<Self>) -> $crate::_std::result::Result<$crate::_std::sync::Arc<_T>, $crate::DowncastError<$crate::_std::sync::Arc<Self>>> |
| 331 | where _T: $crate::AnySync, Self: $crate::DowncastSync<_T> |
| 332 | { |
| 333 | $crate::DowncastSync::<_T>::downcast_arc(self) |
| 334 | } |
| 335 | }; |
| 336 | (<$($params:ident),+ $(,)*> $base:ty $(where $($bounds:tt)+)*) => { |
| 337 | impl<$($params),+> $base |
| 338 | $(where $($bounds)+)* |
| 339 | { |
| 340 | $crate::downcast_sync_methods!(@items); |
| 341 | } |
| 342 | }; |
| 343 | ($base:ty) => { |
| 344 | impl $base { |
| 345 | $crate::downcast_sync_methods!(@items); |
| 346 | } |
| 347 | }; |
| 348 | } |
| 349 | |
| 350 | |
| 351 | /// Generate `downcast`-methods for your trait-object-type. |
| 352 | /// |
| 353 | /// ```ignore |
| 354 | /// downcast_methods!(Foo); |
| 355 | /// downcast_methods!(<B> Foo<B> where B: Bar); |
| 356 | /// downcast_methods!(<B> Foo<Bar = B>); |
| 357 | /// ``` |
| 358 | /// |
| 359 | /// ```ignore |
| 360 | /// impl dyn Foo { |
| 361 | /// /* impl<B> dyn Foo<B> where B: Bar { */ |
| 362 | /// /* impl<B> dyn Foo<Bar = B> { */ |
| 363 | /// |
| 364 | /// pub fn is<T>(&self) -> bool |
| 365 | /// where T: Any, Self: Downcast<T> |
| 366 | /// { ... } |
| 367 | /// |
| 368 | /// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch> |
| 369 | /// where T: Any, Self: Downcast<T> |
| 370 | /// { ... } |
| 371 | /// |
| 372 | /// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch> |
| 373 | /// where T: Any, Self: Downcast<T> |
| 374 | /// { ... } |
| 375 | /// } |
| 376 | /// ``` |
| 377 | #[cfg (not(feature = "std" ))] |
| 378 | #[macro_export ] |
| 379 | macro_rules! downcast_methods { |
| 380 | ($($tt:tt)+) => { $crate::downcast_methods_core!($($tt)+); } |
| 381 | } |
| 382 | |
| 383 | /// Generate `downcast`-methods for your trait-object-type. |
| 384 | /// |
| 385 | /// ```ignore |
| 386 | /// downcast_methods!(Foo); |
| 387 | /// downcast_methods!(<B> Foo<B> where B: Bar); |
| 388 | /// downcast_methods!(<B> Foo<Bar = B>); |
| 389 | /// ``` |
| 390 | /// |
| 391 | /// ```ignore |
| 392 | /// impl dyn Foo { |
| 393 | /// /* impl<B> dyn Foo<B> where B: Bar { */ |
| 394 | /// /* impl<B> dyn Foo<Bar = B> { */ |
| 395 | /// |
| 396 | /// pub fn is<T>(&self) -> bool |
| 397 | /// where T: Any, Self: Downcast<T> |
| 398 | /// { ... } |
| 399 | /// |
| 400 | /// pub fn downcast_ref<T>(&self) -> Result<&T, TypeMismatch> |
| 401 | /// where T: Any, Self: Downcast<T> |
| 402 | /// { ... } |
| 403 | /// |
| 404 | /// pub fn downcast_mut<T>(&mut self) -> Result<&mut T, TypeMismatch> |
| 405 | /// where T: Any, Self: Downcast<T> |
| 406 | /// { ... } |
| 407 | /// |
| 408 | /// pub fn downcast<T>(self: Box<Self>) -> Result<Box<T>, DowncastError<Box<T>>> |
| 409 | /// where T: Any, Self: Downcast<T> |
| 410 | /// { ... } |
| 411 | /// } |
| 412 | /// ``` |
| 413 | #[cfg (feature = "std" )] |
| 414 | #[macro_export ] |
| 415 | macro_rules! downcast_methods { |
| 416 | ($($tt:tt)+) => { $crate::downcast_methods_std!($($tt)+); } |
| 417 | } |
| 418 | |
| 419 | /// Implements [`Downcast`](trait.Downcast.html) and generates |
| 420 | /// `downcast`-methods for your trait-object-type. |
| 421 | /// |
| 422 | /// See [`impl_downcast`](macro.impl_downcast.html), |
| 423 | /// [`downcast_methods`](macro.downcast_methods.html). |
| 424 | #[macro_export ] |
| 425 | macro_rules! downcast { |
| 426 | ($($tt:tt)+) => { |
| 427 | $crate::impl_downcast!($($tt)+); |
| 428 | $crate::downcast_methods!($($tt)+); |
| 429 | } |
| 430 | } |
| 431 | |
| 432 | /// Implements [`DowncastSync`](trait.DowncastSync.html) and generates |
| 433 | /// `downcast`-methods for your trait-object-type. |
| 434 | /// |
| 435 | /// See [`impl_downcast_sync`](macro.impl_downcast.html), |
| 436 | /// [`downcast_sync_methods`](macro.downcast_methods.html). |
| 437 | #[cfg (feature = "std" )] |
| 438 | #[macro_export ] |
| 439 | macro_rules! downcast_sync { |
| 440 | ($($tt:tt)+) => { |
| 441 | $crate::impl_downcast_sync!($($tt)+); |
| 442 | $crate::downcast_sync_methods!($($tt)+); |
| 443 | } |
| 444 | } |
| 445 | |
| 446 | // NOTE: We only implement the trait, because implementing the methods won't |
| 447 | // be possible when we replace downcast::Any by std::any::Any. |
| 448 | downcast!(dyn Any); |
| 449 | downcast!((dyn Any + Send)); |
| 450 | downcast!((dyn Any + Sync)); |
| 451 | #[cfg (feature = "std" )] |
| 452 | downcast_sync!(dyn AnySync); |
| 453 | |
| 454 | |