Skip to main content

intertrait/
lib.rs

1#![no_std]
2//!
3//! This library provides direct casting among trait objects implemented by a type.
4//!
5//! ## std usage
6//!
7//! This crate is intended for `no_std` usage only.
8//!
9//! Using this crate in a `std` environment will break.
10//!
11//! If you need `std` usage, use the original `intertrait` crate instead.
12//!
13//! For full details, refer to the original README and docs.
14extern crate alloc;
15
16use alloc::boxed::Box;
17use alloc::rc::Rc;
18use alloc::sync::Arc;
19use core::any::{Any, TypeId};
20
21use hashbrown::HashMap;
22use linkme::distributed_slice;
23use spin::Lazy;
24
25pub use intertrait_macros::*;
26
27use crate::hasher::BuildFastHasher;
28
29pub mod cast;
30mod hasher;
31
32#[doc(hidden)]
33pub type BoxedCaster = Box<dyn Any + Send + Sync>;
34
35#[doc(hidden)]
36pub mod __private {
37    pub use alloc::boxed::Box;
38    pub use linkme;
39}
40
41#[cfg(doctest)]
42doc_comment::doctest!("../README.md");
43
44/// A distributed slice gathering constructor functions for [`Caster<T>`]s.
45///
46/// A constructor function returns `TypeId` of a concrete type involved in the casting
47/// and a `Box` of a trait object backed by a [`Caster<T>`].
48///
49/// [`Caster<T>`]: ./struct.Caster.html
50#[doc(hidden)]
51#[distributed_slice]
52pub static CASTERS: [fn() -> (TypeId, BoxedCaster)] = [..];
53
54/// A `HashMap` mapping `TypeId` of a [`Caster<T>`] to an instance of it.
55///
56/// [`Caster<T>`]: ./struct.Caster.html
57static CASTER_MAP: Lazy<HashMap<(TypeId, TypeId), BoxedCaster, BuildFastHasher>> =
58    Lazy::new(|| {
59        CASTERS
60            .iter()
61            .map(|f| {
62                let (type_id, caster) = f();
63                ((type_id, (*caster).type_id()), caster)
64            })
65            .collect()
66    });
67
68fn cast_arc_panic<T: ?Sized + 'static>(_: Arc<dyn Any + Sync + Send>) -> Arc<T> {
69    panic!("Prepend [sync] to the list of target traits for Sync + Send types")
70}
71
72/// A `Caster` knows how to cast a reference to or `Box` of a trait object for `Any`
73/// to a trait object of trait `T`. Each `Caster` instance is specific to a concrete type.
74/// That is, it knows how to cast to single specific trait implemented by single specific type.
75///
76/// An implementation of a trait for a concrete type doesn't need to manually provide
77/// a `Caster`. Instead attach `#[cast_to]` to the `impl` block.
78#[doc(hidden)]
79pub struct Caster<T: ?Sized + 'static> {
80    /// Casts an immutable reference to a trait object for `Any` to a reference
81    /// to a trait object for trait `T`.
82    pub cast_ref: fn(from: &dyn Any) -> &T,
83
84    /// Casts a mutable reference to a trait object for `Any` to a mutable reference
85    /// to a trait object for trait `T`.
86    pub cast_mut: fn(from: &mut dyn Any) -> &mut T,
87
88    /// Casts a `Box` holding a trait object for `Any` to another `Box` holding a trait object
89    /// for trait `T`.
90    pub cast_box: fn(from: Box<dyn Any>) -> Box<T>,
91
92    /// Casts an `Rc` holding a trait object for `Any` to another `Rc` holding a trait object
93    /// for trait `T`.
94    pub cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
95
96    /// Casts an `Arc` holding a trait object for `Any + Sync + Send + 'static`
97    /// to another `Arc` holding a trait object for trait `T`.
98    pub cast_arc: fn(from: Arc<dyn Any + Sync + Send + 'static>) -> Arc<T>,
99}
100
101impl<T: ?Sized + 'static> Caster<T> {
102    pub fn new(
103        cast_ref: fn(from: &dyn Any) -> &T,
104        cast_mut: fn(from: &mut dyn Any) -> &mut T,
105        cast_box: fn(from: Box<dyn Any>) -> Box<T>,
106        cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
107    ) -> Caster<T> {
108        Caster::<T> {
109            cast_ref,
110            cast_mut,
111            cast_box,
112            cast_rc,
113            cast_arc: cast_arc_panic,
114        }
115    }
116
117    pub fn new_sync(
118        cast_ref: fn(from: &dyn Any) -> &T,
119        cast_mut: fn(from: &mut dyn Any) -> &mut T,
120        cast_box: fn(from: Box<dyn Any>) -> Box<T>,
121        cast_rc: fn(from: Rc<dyn Any>) -> Rc<T>,
122        cast_arc: fn(from: Arc<dyn Any + Sync + Send>) -> Arc<T>,
123    ) -> Caster<T> {
124        Caster::<T> {
125            cast_ref,
126            cast_mut,
127            cast_box,
128            cast_rc,
129            cast_arc,
130        }
131    }
132}
133
134/// Returns a `Caster<S, T>` from a concrete type `S` to a trait `T` implemented by it.
135fn caster<T: ?Sized + 'static>(type_id: TypeId) -> Option<&'static Caster<T>> {
136    CASTER_MAP
137        .get(&(type_id, TypeId::of::<Caster<T>>()))
138        .and_then(|caster| caster.downcast_ref::<Caster<T>>())
139}
140
141/// `CastFrom` must be extended by a trait that wants to allow for casting into another trait.
142///
143/// It is used for obtaining a trait object for [`Any`] from a trait object for its sub-trait,
144/// and blanket implemented for all `Sized + Any + 'static` types.
145///
146/// # Examples
147/// ```ignore
148/// trait Source: CastFrom {
149///     ...
150/// }
151/// ```
152pub trait CastFrom: Any + 'static {
153    /// Returns a immutable reference to `Any`, which is backed by the type implementing this trait.
154    fn ref_any(&self) -> &dyn Any;
155
156    /// Returns a mutable reference to `Any`, which is backed by the type implementing this trait.
157    fn mut_any(&mut self) -> &mut dyn Any;
158
159    /// Returns a `Box` of `Any`, which is backed by the type implementing this trait.
160    fn box_any(self: Box<Self>) -> Box<dyn Any>;
161
162    /// Returns an `Rc` of `Any`, which is backed by the type implementing this trait.
163    fn rc_any(self: Rc<Self>) -> Rc<dyn Any>;
164}
165
166/// `CastFromSync` must be extended by a trait that is `Any + Sync + Send + 'static`
167/// and wants to allow for casting into another trait behind references and smart pointers
168/// especially including `Arc`.
169///
170/// It is used for obtaining a trait object for [`Any + Sync + Send + 'static`] from an object
171/// for its sub-trait, and blanket implemented for all `Sized + Sync + Send + 'static` types.
172///
173/// # Examples
174/// ```ignore
175/// trait Source: CastFromSync {
176///     ...
177/// }
178/// ```
179pub trait CastFromSync: CastFrom + Sync + Send + 'static {
180    fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static>;
181}
182
183impl<T: Sized + Any + 'static> CastFrom for T {
184    fn ref_any(&self) -> &dyn Any {
185        self
186    }
187
188    fn mut_any(&mut self) -> &mut dyn Any {
189        self
190    }
191
192    fn box_any(self: Box<Self>) -> Box<dyn Any> {
193        self
194    }
195
196    fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
197        self
198    }
199}
200
201impl CastFrom for dyn Any + 'static {
202    fn ref_any(&self) -> &dyn Any {
203        self
204    }
205
206    fn mut_any(&mut self) -> &mut dyn Any {
207        self
208    }
209
210    fn box_any(self: Box<Self>) -> Box<dyn Any> {
211        self
212    }
213
214    fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
215        self
216    }
217}
218
219impl<T: Sized + Sync + Send + 'static> CastFromSync for T {
220    fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
221        self
222    }
223}
224
225impl CastFrom for dyn Any + Sync + Send + 'static {
226    fn ref_any(&self) -> &dyn Any {
227        self
228    }
229
230    fn mut_any(&mut self) -> &mut dyn Any {
231        self
232    }
233
234    fn box_any(self: Box<Self>) -> Box<dyn Any> {
235        self
236    }
237
238    fn rc_any(self: Rc<Self>) -> Rc<dyn Any> {
239        self
240    }
241}
242
243impl CastFromSync for dyn Any + Sync + Send + 'static {
244    fn arc_any(self: Arc<Self>) -> Arc<dyn Any + Sync + Send + 'static> {
245        self
246    }
247}
248
249#[cfg(test)]
250extern crate std;
251
252#[cfg(test)]
253mod tests {
254    use std::any::{Any, TypeId};
255    use std::fmt::{Debug, Display};
256
257    use linkme::distributed_slice;
258
259    use crate::{BoxedCaster, CastFromSync};
260
261    use super::cast::*;
262    use super::*;
263
264    #[distributed_slice(super::CASTERS)]
265    static TEST_CASTER: fn() -> (TypeId, BoxedCaster) = create_test_caster;
266
267    #[derive(Debug)]
268    struct TestStruct;
269
270    trait SourceTrait: CastFromSync {}
271
272    impl SourceTrait for TestStruct {}
273
274    fn create_test_caster() -> (TypeId, BoxedCaster) {
275        let type_id = TypeId::of::<TestStruct>();
276        let caster = Box::new(Caster::<dyn Debug> {
277            cast_ref: |from| from.downcast_ref::<TestStruct>().unwrap(),
278            cast_mut: |from| from.downcast_mut::<TestStruct>().unwrap(),
279            cast_box: |from| from.downcast::<TestStruct>().unwrap(),
280            cast_rc: |from| from.downcast::<TestStruct>().unwrap(),
281            cast_arc: |from| from.downcast::<TestStruct>().unwrap(),
282        });
283        (type_id, caster)
284    }
285
286    #[test]
287    fn cast_ref() {
288        let ts = TestStruct;
289        let st: &dyn SourceTrait = &ts;
290        let debug = st.cast::<dyn Debug>();
291        assert!(debug.is_some());
292    }
293
294    #[test]
295    fn cast_mut() {
296        let mut ts = TestStruct;
297        let st: &mut dyn SourceTrait = &mut ts;
298        let debug = st.cast::<dyn Debug>();
299        assert!(debug.is_some());
300    }
301
302    #[test]
303    fn cast_box() {
304        let ts = Box::new(TestStruct);
305        let st: Box<dyn SourceTrait> = ts;
306        let debug = st.cast::<dyn Debug>();
307        assert!(debug.is_ok());
308    }
309
310    #[test]
311    fn cast_rc() {
312        let ts = Rc::new(TestStruct);
313        let st: Rc<dyn SourceTrait> = ts;
314        let debug = st.cast::<dyn Debug>();
315        assert!(debug.is_ok());
316    }
317
318    #[test]
319    fn cast_arc() {
320        let ts = Arc::new(TestStruct);
321        let st: Arc<dyn SourceTrait> = ts;
322        let debug = st.cast::<dyn Debug>();
323        assert!(debug.is_ok());
324    }
325
326    #[test]
327    fn cast_ref_wrong() {
328        let ts = TestStruct;
329        let st: &dyn SourceTrait = &ts;
330        let display = st.cast::<dyn Display>();
331        assert!(display.is_none());
332    }
333
334    #[test]
335    fn cast_mut_wrong() {
336        let mut ts = TestStruct;
337        let st: &mut dyn SourceTrait = &mut ts;
338        let display = st.cast::<dyn Display>();
339        assert!(display.is_none());
340    }
341
342    #[test]
343    fn cast_box_wrong() {
344        let ts = Box::new(TestStruct);
345        let st: Box<dyn SourceTrait> = ts;
346        let display = st.cast::<dyn Display>();
347        assert!(display.is_err());
348    }
349
350    #[test]
351    fn cast_rc_wrong() {
352        let ts = Rc::new(TestStruct);
353        let st: Rc<dyn SourceTrait> = ts;
354        let display = st.cast::<dyn Display>();
355        assert!(display.is_err());
356    }
357
358    #[test]
359    fn cast_arc_wrong() {
360        let ts = Arc::new(TestStruct);
361        let st: Arc<dyn SourceTrait> = ts;
362        let display = st.cast::<dyn Display>();
363        assert!(display.is_err());
364    }
365
366    #[test]
367    fn cast_ref_from_any() {
368        let ts = TestStruct;
369        let st: &dyn Any = &ts;
370        let debug = st.cast::<dyn Debug>();
371        assert!(debug.is_some());
372    }
373
374    #[test]
375    fn cast_mut_from_any() {
376        let mut ts = TestStruct;
377        let st: &mut dyn Any = &mut ts;
378        let debug = st.cast::<dyn Debug>();
379        assert!(debug.is_some());
380    }
381
382    #[test]
383    fn cast_box_from_any() {
384        let ts = Box::new(TestStruct);
385        let st: Box<dyn Any> = ts;
386        let debug = st.cast::<dyn Debug>();
387        assert!(debug.is_ok());
388    }
389
390    #[test]
391    fn cast_rc_from_any() {
392        let ts = Rc::new(TestStruct);
393        let st: Rc<dyn Any> = ts;
394        let debug = st.cast::<dyn Debug>();
395        assert!(debug.is_ok());
396    }
397
398    #[test]
399    fn cast_arc_from_any() {
400        let ts = Arc::new(TestStruct);
401        let st: Arc<dyn Any + Send + Sync> = ts;
402        let debug = st.cast::<dyn Debug>();
403        assert!(debug.is_ok());
404    }
405
406    #[test]
407    fn impls_ref() {
408        let ts = TestStruct;
409        let st: &dyn SourceTrait = &ts;
410        assert!(st.impls::<dyn Debug>());
411    }
412
413    #[test]
414    fn impls_mut() {
415        let mut ts = TestStruct;
416        let st: &mut dyn SourceTrait = &mut ts;
417        assert!((*st).impls::<dyn Debug>());
418    }
419
420    #[test]
421    fn impls_box() {
422        let ts = Box::new(TestStruct);
423        let st: Box<dyn SourceTrait> = ts;
424        assert!((*st).impls::<dyn Debug>());
425    }
426
427    #[test]
428    fn impls_rc() {
429        let ts = Rc::new(TestStruct);
430        let st: Rc<dyn SourceTrait> = ts;
431        assert!((*st).impls::<dyn Debug>());
432    }
433
434    #[test]
435    fn impls_arc() {
436        let ts = Arc::new(TestStruct);
437        let st: Arc<dyn SourceTrait> = ts;
438        assert!((*st).impls::<dyn Debug>());
439    }
440
441    #[test]
442    fn impls_not_ref() {
443        let ts = TestStruct;
444        let st: &dyn SourceTrait = &ts;
445        assert!(!st.impls::<dyn Display>());
446    }
447
448    #[test]
449    fn impls_not_mut() {
450        let mut ts = TestStruct;
451        let st: &mut dyn Any = &mut ts;
452        assert!(!(*st).impls::<dyn Display>());
453    }
454
455    #[test]
456    fn impls_not_box() {
457        let ts = Box::new(TestStruct);
458        let st: Box<dyn SourceTrait> = ts;
459        assert!(!st.impls::<dyn Display>());
460    }
461
462    #[test]
463    fn impls_not_rc() {
464        let ts = Rc::new(TestStruct);
465        let st: Rc<dyn SourceTrait> = ts;
466        assert!(!(*st).impls::<dyn Display>());
467    }
468
469    #[test]
470    fn impls_not_arc() {
471        let ts = Arc::new(TestStruct);
472        let st: Arc<dyn SourceTrait> = ts;
473        assert!(!(*st).impls::<dyn Display>());
474    }
475}