1#![deny(unsafe_code)]
2#![cfg_attr(not(feature = "std"), no_std)]
3#[doc(hidden)]
163#[cfg(not(feature = "std"))]
164pub extern crate core as __std;
165#[doc(hidden)]
166#[cfg(feature = "std")]
167pub extern crate std as __std;
168#[doc(hidden)]
169pub extern crate alloc as __alloc;
170
171use __std::any::Any;
172use __alloc::{boxed::Box, rc::Rc, sync::Arc};
173
174pub trait Downcast: Any {
176 fn into_any(self: Box<Self>) -> Box<dyn Any>;
179 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any>;
182 fn as_any(&self) -> &dyn Any;
185 fn as_any_mut(&mut self) -> &mut dyn Any;
188}
189
190impl<T: Any> Downcast for T {
191 fn into_any(self: Box<Self>) -> Box<dyn Any> { self }
192 fn into_any_rc(self: Rc<Self>) -> Rc<dyn Any> { self }
193 fn as_any(&self) -> &dyn Any { self }
194 fn as_any_mut(&mut self) -> &mut dyn Any { self }
195}
196
197pub trait DowncastSync: Downcast + Send + Sync {
199 fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
202}
203
204impl<T: Any + Send + Sync> DowncastSync for T {
205 fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> { self }
206}
207
208#[macro_export(local_inner_macros)]
214macro_rules! impl_downcast {
215 (@impl_full
216 $trait_:ident [$($param_types:tt)*]
217 for [$($forall_types:ident),*]
218 where [$($preds:tt)*]
219 ) => {
220 impl_downcast! {
221 @inject_where
222 [impl<$($forall_types),*> dyn $trait_<$($param_types)*>]
223 types [$($forall_types),*]
224 where [$($preds)*]
225 [{
226 impl_downcast! { @impl_body $trait_ [$($param_types)*] }
227 }]
228 }
229 };
230
231 (@impl_full_sync
232 $trait_:ident [$($param_types:tt)*]
233 for [$($forall_types:ident),*]
234 where [$($preds:tt)*]
235 ) => {
236 impl_downcast! {
237 @inject_where
238 [impl<$($forall_types),*> dyn $trait_<$($param_types)*>]
239 types [$($forall_types),*]
240 where [$($preds)*]
241 [{
242 impl_downcast! { @impl_body $trait_ [$($param_types)*] }
243 impl_downcast! { @impl_body_sync $trait_ [$($param_types)*] }
244 }]
245 }
246 };
247
248 (@impl_body $trait_:ident [$($types:tt)*]) => {
249 #[inline]
251 pub fn is<__T: $trait_<$($types)*>>(&self) -> bool {
252 $crate::Downcast::as_any(self).is::<__T>()
253 }
254 #[inline]
257 pub fn downcast<__T: $trait_<$($types)*>>(
258 self: $crate::__alloc::boxed::Box<Self>
259 ) -> $crate::__std::result::Result<$crate::__alloc::boxed::Box<__T>, $crate::__alloc::boxed::Box<Self>> {
260 if self.is::<__T>() {
261 Ok($crate::Downcast::into_any(self).downcast::<__T>().unwrap())
262 } else {
263 Err(self)
264 }
265 }
266 #[inline]
269 pub fn downcast_rc<__T: $trait_<$($types)*>>(
270 self: $crate::__alloc::rc::Rc<Self>
271 ) -> $crate::__std::result::Result<$crate::__alloc::rc::Rc<__T>, $crate::__alloc::rc::Rc<Self>> {
272 if self.is::<__T>() {
273 Ok($crate::Downcast::into_any_rc(self).downcast::<__T>().unwrap())
274 } else {
275 Err(self)
276 }
277 }
278 #[inline]
281 pub fn downcast_ref<__T: $trait_<$($types)*>>(&self) -> $crate::__std::option::Option<&__T> {
282 $crate::Downcast::as_any(self).downcast_ref::<__T>()
283 }
284 #[inline]
287 pub fn downcast_mut<__T: $trait_<$($types)*>>(&mut self) -> $crate::__std::option::Option<&mut __T> {
288 $crate::Downcast::as_any_mut(self).downcast_mut::<__T>()
289 }
290 };
291
292 (@impl_body_sync $trait_:ident [$($types:tt)*]) => {
293 #[inline]
296 pub fn downcast_arc<__T: $trait_<$($types)*>>(
297 self: $crate::__alloc::sync::Arc<Self>,
298 ) -> $crate::__std::result::Result<$crate::__alloc::sync::Arc<__T>, $crate::__alloc::sync::Arc<Self>>
299 where __T: $crate::__std::any::Any + $crate::__std::marker::Send + $crate::__std::marker::Sync
300 {
301 if self.is::<__T>() {
302 Ok($crate::DowncastSync::into_any_arc(self).downcast::<__T>().unwrap())
303 } else {
304 Err(self)
305 }
306 }
307 };
308
309 (@inject_where [$($before:tt)*] types [] where [] [$($after:tt)*]) => {
310 impl_downcast! { @as_item $($before)* $($after)* }
311 };
312
313 (@inject_where [$($before:tt)*] types [$($types:ident),*] where [] [$($after:tt)*]) => {
314 impl_downcast! {
315 @as_item
316 $($before)*
317 where $( $types: $crate::__std::any::Any + 'static ),*
318 $($after)*
319 }
320 };
321 (@inject_where [$($before:tt)*] types [$($types:ident),*] where [$($preds:tt)+] [$($after:tt)*]) => {
322 impl_downcast! {
323 @as_item
324 $($before)*
325 where
326 $( $types: $crate::__std::any::Any + 'static, )*
327 $($preds)*
328 $($after)*
329 }
330 };
331
332 (@as_item $i:item) => { $i };
333
334 ($trait_:ident ) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
336 ($trait_:ident <>) => { impl_downcast! { @impl_full $trait_ [] for [] where [] } };
337 (sync $trait_:ident ) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
338 (sync $trait_:ident <>) => { impl_downcast! { @impl_full_sync $trait_ [] for [] where [] } };
339 ($trait_:ident < $($types:ident),* >) => {
341 impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [] }
342 };
343 (sync $trait_:ident < $($types:ident),* >) => {
344 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [] }
345 };
346 ($trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
348 impl_downcast! { @impl_full $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
349 };
350 (sync $trait_:ident < $($types:ident),* > where $($preds:tt)+) => {
351 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [$($types),*] where [$($preds)*] }
352 };
353 ($trait_:ident assoc $($atypes:ident),*) => {
355 impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
356 };
357 (sync $trait_:ident assoc $($atypes:ident),*) => {
358 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [] }
359 };
360 ($trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
362 impl_downcast! { @impl_full $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
363 };
364 (sync $trait_:ident assoc $($atypes:ident),* where $($preds:tt)+) => {
365 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $atypes),*] for [$($atypes),*] where [$($preds)*] }
366 };
367 ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
369 impl_downcast! {
370 @impl_full
371 $trait_ [$($types),*, $($atypes = $atypes),*]
372 for [$($types),*, $($atypes),*]
373 where []
374 }
375 };
376 (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),*) => {
377 impl_downcast! {
378 @impl_full_sync
379 $trait_ [$($types),*, $($atypes = $atypes),*]
380 for [$($types),*, $($atypes),*]
381 where []
382 }
383 };
384 ($trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
386 impl_downcast! {
387 @impl_full
388 $trait_ [$($types),*, $($atypes = $atypes),*]
389 for [$($types),*, $($atypes),*]
390 where [$($preds)*]
391 }
392 };
393 (sync $trait_:ident < $($types:ident),* > assoc $($atypes:ident),* where $($preds:tt)+) => {
394 impl_downcast! {
395 @impl_full_sync
396 $trait_ [$($types),*, $($atypes = $atypes),*]
397 for [$($types),*, $($atypes),*]
398 where [$($preds)*]
399 }
400 };
401 (concrete $trait_:ident < $($types:ident),* >) => {
403 impl_downcast! { @impl_full $trait_ [$($types),*] for [] where [] }
404 };
405 (sync concrete $trait_:ident < $($types:ident),* >) => {
406 impl_downcast! { @impl_full_sync $trait_ [$($types),*] for [] where [] }
407 };
408 (concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
410 impl_downcast! { @impl_full $trait_ [$($atypes = $aty),*] for [] where [] }
411 };
412 (sync concrete $trait_:ident assoc $($atypes:ident = $aty:ty),*) => {
413 impl_downcast! { @impl_full_sync $trait_ [$($atypes = $aty),*] for [] where [] }
414 };
415 (concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
417 impl_downcast! { @impl_full $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
418 };
419 (sync concrete $trait_:ident < $($types:ident),* > assoc $($atypes:ident = $aty:ty),*) => {
420 impl_downcast! { @impl_full_sync $trait_ [$($types),*, $($atypes = $aty),*] for [] where [] }
421 };
422}
423
424
425#[cfg(test)]
426mod test {
427 macro_rules! test_mod {
428 (
429 $test_mod_name:ident,
430 trait $base_trait:path { $($base_impl:tt)* },
431 non_sync: { $($non_sync_def:tt)+ },
432 sync: { $($sync_def:tt)+ }
433 ) => {
434 test_mod! {
435 $test_mod_name,
436 trait $base_trait { $($base_impl:tt)* },
437 type dyn $base_trait,
438 non_sync: { $($non_sync_def)* },
439 sync: { $($sync_def)* }
440 }
441 };
442
443 (
444 $test_mod_name:ident,
445 trait $base_trait:path { $($base_impl:tt)* },
446 type $base_type:ty,
447 non_sync: { $($non_sync_def:tt)+ },
448 sync: { $($sync_def:tt)+ }
449 ) => {
450 mod $test_mod_name {
451 test_mod!(
452 @test
453 $test_mod_name,
454 test_name: test_non_sync,
455 trait $base_trait { $($base_impl)* },
456 type $base_type,
457 { $($non_sync_def)+ },
458 []);
459
460 test_mod!(
461 @test
462 $test_mod_name,
463 test_name: test_sync,
464 trait $base_trait { $($base_impl)* },
465 type $base_type,
466 { $($sync_def)+ },
467 [{
468 let arc: $crate::__alloc::sync::Arc<$base_type> = $crate::__alloc::sync::Arc::new(Foo(42));
470 let res = arc.downcast_arc::<Bar>();
471 assert!(res.is_err());
472 let arc = res.unwrap_err();
473 assert_eq!(
475 42, arc.downcast_arc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
476 }]);
477 }
478 };
479
480 (
481 @test
482 $test_mod_name:ident,
483 test_name: $test_name:ident,
484 trait $base_trait:path { $($base_impl:tt)* },
485 type $base_type:ty,
486 { $($def:tt)+ },
487 [ $($more_tests:block)* ]
488 ) => {
489 #[test]
490 fn $test_name() {
491 #[allow(unused_imports)]
492 use super::super::{Downcast, DowncastSync};
493
494 #[allow(dead_code)] struct Any;
497 #[allow(dead_code)] struct Arc;
498 #[allow(dead_code)] struct Box;
499 #[allow(dead_code)] struct Option;
500 #[allow(dead_code)] struct Result;
501 #[allow(dead_code)] struct Rc;
502 #[allow(dead_code)] struct Send;
503 #[allow(dead_code)] struct Sync;
504
505 $($def)*
507
508 #[derive(Debug)]
510 struct Foo(u32);
511 impl $base_trait for Foo { $($base_impl)* }
512 #[derive(Debug)]
513 struct Bar(f64);
514 impl $base_trait for Bar { $($base_impl)* }
515
516 fn get_val(base: &$crate::__alloc::boxed::Box<$base_type>) -> u32 {
518 match base.downcast_ref::<Foo>() {
519 Some(val) => val.0,
520 None => 0
521 }
522 }
523 fn set_val(base: &mut $crate::__alloc::boxed::Box<$base_type>, val: u32) {
524 if let Some(foo) = base.downcast_mut::<Foo>() {
525 foo.0 = val;
526 }
527 }
528
529 let mut base: $crate::__alloc::boxed::Box<$base_type> = $crate::__alloc::boxed::Box::new(Foo(42));
530 assert_eq!(get_val(&base), 42);
531
532 if let Some(foo) = base.downcast_ref::<Foo>() {
534 assert_eq!(foo.0, 42);
535 } else if let Some(bar) = base.downcast_ref::<Bar>() {
536 assert_eq!(bar.0, 42.0);
537 }
538
539 set_val(&mut base, 6*9);
540 assert_eq!(get_val(&base), 6*9);
541
542 assert!(base.is::<Foo>());
543
544 let res = base.downcast::<Bar>();
546 assert!(res.is_err());
547 let base = res.unwrap_err();
548 assert_eq!(
550 6*9, base.downcast::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
551
552 let rc: $crate::__alloc::rc::Rc<$base_type> = $crate::__alloc::rc::Rc::new(Foo(42));
554 let res = rc.downcast_rc::<Bar>();
555 assert!(res.is_err());
556 let rc = res.unwrap_err();
557 assert_eq!(
559 42, rc.downcast_rc::<Foo>().map_err(|_| "Shouldn't happen.").unwrap().0);
560
561 $($more_tests)*
562 }
563 };
564 (
565 $test_mod_name:ident,
566 trait $base_trait:path { $($base_impl:tt)* },
567 non_sync: { $($non_sync_def:tt)+ },
568 sync: { $($sync_def:tt)+ }
569 ) => {
570 test_mod! {
571 $test_mod_name,
572 trait $base_trait { $($base_impl:tt)* },
573 type $base_trait,
574 non_sync: { $($non_sync_def)* },
575 sync: { $($sync_def)* }
576 }
577 };
578
579 }
580
581 test_mod!(non_generic, trait Base {},
582 non_sync: {
583 trait Base: Downcast {}
584 impl_downcast!(Base);
585 },
586 sync: {
587 trait Base: DowncastSync {}
588 impl_downcast!(sync Base);
589 });
590
591 test_mod!(generic, trait Base<u32> {},
592 non_sync: {
593 trait Base<T>: Downcast {}
594 impl_downcast!(Base<T>);
595 },
596 sync: {
597 trait Base<T>: DowncastSync {}
598 impl_downcast!(sync Base<T>);
599 });
600
601 test_mod!(constrained_generic, trait Base<u32> {},
602 non_sync: {
603 trait Base<T: Copy>: Downcast {}
604 impl_downcast!(Base<T> where T: Copy);
605 },
606 sync: {
607 trait Base<T: Copy>: DowncastSync {}
608 impl_downcast!(sync Base<T> where T: Copy);
609 });
610
611 test_mod!(associated,
612 trait Base { type H = f32; },
613 type dyn Base<H=f32>,
614 non_sync: {
615 trait Base: Downcast { type H; }
616 impl_downcast!(Base assoc H);
617 },
618 sync: {
619 trait Base: DowncastSync { type H; }
620 impl_downcast!(sync Base assoc H);
621 });
622
623 test_mod!(constrained_associated,
624 trait Base { type H = f32; },
625 type dyn Base<H=f32>,
626 non_sync: {
627 trait Base: Downcast { type H: Copy; }
628 impl_downcast!(Base assoc H where H: Copy);
629 },
630 sync: {
631 trait Base: DowncastSync { type H: Copy; }
632 impl_downcast!(sync Base assoc H where H: Copy);
633 });
634
635 test_mod!(param_and_associated,
636 trait Base<u32> { type H = f32; },
637 type dyn Base<u32, H=f32>,
638 non_sync: {
639 trait Base<T>: Downcast { type H; }
640 impl_downcast!(Base<T> assoc H);
641 },
642 sync: {
643 trait Base<T>: DowncastSync { type H; }
644 impl_downcast!(sync Base<T> assoc H);
645 });
646
647 test_mod!(constrained_param_and_associated,
648 trait Base<u32> { type H = f32; },
649 type dyn Base<u32, H=f32>,
650 non_sync: {
651 trait Base<T: Clone>: Downcast { type H: Copy; }
652 impl_downcast!(Base<T> assoc H where T: Clone, H: Copy);
653 },
654 sync: {
655 trait Base<T: Clone>: DowncastSync { type H: Copy; }
656 impl_downcast!(sync Base<T> assoc H where T: Clone, H: Copy);
657 });
658
659 test_mod!(concrete_parametrized, trait Base<u32> {},
660 non_sync: {
661 trait Base<T>: Downcast {}
662 impl_downcast!(concrete Base<u32>);
663 },
664 sync: {
665 trait Base<T>: DowncastSync {}
666 impl_downcast!(sync concrete Base<u32>);
667 });
668
669 test_mod!(concrete_associated,
670 trait Base { type H = u32; },
671 type dyn Base<H=u32>,
672 non_sync: {
673 trait Base: Downcast { type H; }
674 impl_downcast!(concrete Base assoc H=u32);
675 },
676 sync: {
677 trait Base: DowncastSync { type H; }
678 impl_downcast!(sync concrete Base assoc H=u32);
679 });
680
681 test_mod!(concrete_parametrized_associated,
682 trait Base<u32> { type H = f32; },
683 type dyn Base<u32, H=f32>,
684 non_sync: {
685 trait Base<T>: Downcast { type H; }
686 impl_downcast!(concrete Base<u32> assoc H=f32);
687 },
688 sync: {
689 trait Base<T>: DowncastSync { type H; }
690 impl_downcast!(sync concrete Base<u32> assoc H=f32);
691 });
692}