Skip to main content

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}