intertrait/cast/cast_ref.rs
1use core::any::TypeId;
2
3use crate::{caster, CastFrom, Caster, CASTER_MAP};
4
5/// A trait that is blanket-implemented for traits extending `CastFrom` to allow for casting
6/// of a trait object for it behind an immutable reference to a trait object for another trait
7/// implemented by the underlying value.
8///
9/// # Examples
10/// ## Casting an immutable reference
11/// ```
12/// # use intertrait::*;
13/// use intertrait::cast::*;
14///
15/// # #[cast_to(Greet)]
16/// # struct Data;
17/// # trait Source: CastFrom {}
18/// # trait Greet {
19/// # fn greet(&self);
20/// # }
21/// # impl Greet for Data {
22/// # fn greet(&self) {
23/// # println!("Hello");
24/// # }
25/// # }
26/// impl Source for Data {}
27/// let data = Data;
28/// let source: &dyn Source = &data;
29/// let greet = source.cast::<dyn Greet>();
30/// greet.unwrap().greet();
31/// ```
32///
33/// ## Testing if a cast is possible
34/// ```
35/// # use intertrait::*;
36/// use intertrait::cast::*;
37///
38/// # #[cast_to(Greet)]
39/// # struct Data;
40/// # trait Source: CastFrom {}
41/// # trait Greet {
42/// # fn greet(&self);
43/// # }
44/// # impl Greet for Data {
45/// # fn greet(&self) {
46/// # println!("Hello");
47/// # }
48/// # }
49/// impl Source for Data {}
50/// let data = Data;
51/// let source: &dyn Source = &data;
52/// assert!(source.impls::<dyn Greet>());
53/// assert!(!source.impls::<dyn std::fmt::Debug>());
54/// ```
55pub trait CastRef {
56 /// Casts a reference to this trait into that of type `T`.
57 fn cast<T: ?Sized + 'static>(&self) -> Option<&T>;
58
59 /// Tests if this trait object can be cast into `T`.
60 fn impls<T: ?Sized + 'static>(&self) -> bool;
61}
62
63/// A blanket implementation of `CastRef` for traits extending `CastFrom`.
64impl<S: ?Sized + CastFrom> CastRef for S {
65 fn cast<T: ?Sized + 'static>(&self) -> Option<&T> {
66 let any = self.ref_any();
67 let caster = caster::<T>(any.type_id())?;
68 (caster.cast_ref)(any).into()
69 }
70
71 fn impls<T: ?Sized + 'static>(&self) -> bool {
72 CASTER_MAP.contains_key(&(self.type_id(), TypeId::of::<Caster<T>>()))
73 }
74}