any_trait/lib.rs
1//! # AnyTrait
2//!
3//! **AnyTrait** lets you upcast to a generic `&dyn AnyTrait` like
4//! [`::core::any::Any`]\
5//! but instead of just allowing you to downcast back to
6//! the concrete type, it also lets you downcast to any trait used by your type
7//!
8//! *This is not zero-cost, since at any cast we need to go through the
9//! list of all possible subtraits.*
10//!
11//! This will (almost) enable you to do OOP in rust, but if this is your goal
12//! we still ask you to kindly reconsider
13//!
14//! example usage:
15//! ```rust
16//! use any_trait::{AnySubTrait, AnyTrait, AsAnyTrait};
17//! trait TA {}
18//! trait TB : AnyTrait {} // if a trait implements `AnyTrait` you can upcast
19//! #[derive(AnySubTrait)]
20//! #[any_sub_trait(TA, TB)] // must include all traits you want to downcast to
21//! struct Concrete {
22//! // whatever
23//! }
24//! impl TA for Concrete {}
25//! impl TB for Concrete {}
26//! fn test() {
27//! let c = Concrete{};
28//! let a = c.as_anytrait();
29//!
30//! let ta :&dyn TA = a.downcast_ref::<dyn TA>().unwrap();
31//! let tb :&dyn TB = a.downcast_ref::<dyn TB>().unwrap();
32//!
33//! let a2 = tb.as_anytrait();
34//! let c_ref : &Concrete = a2.downcast_ref::<Concrete>().unwrap();
35//! }
36//! ```
37
38#![feature(const_type_name)]
39#![no_std]
40pub mod typeidconst;
41
42use typeidconst::TypeIdConst;
43
44pub use ::any_trait_macro::AnySubTrait;
45
46/// # AnyTrait
47///
48/// **Don't implement manually**
49///
50/// use `#[derive(AnySubTrait)]`
51///
52/// <br/>
53///
54/// Imagine a Concrete type and all its subtraits\
55/// AnyTrait lets you walk up and down the traits safely
56///
57/// With `::core::any::Any` you can only cast between the concrete type
58/// and `Any`.\
59/// With `AnyTrait` you can do that, plus any other trait in the middle
60///
61/// *`AnyTrait` is not necessarily fast as it needs check and track
62/// the list of traits you are allowed to cast to.*
63pub trait AnyTrait: 'static {
64 /// returns a list of all possible traits that you can up/downcast to\
65 /// This list always has at least two elements:
66 /// * id 0: `TypeIdConst::of::<dyn AnyType>`
67 /// * id 1: `TypeIdConst::of::<YourConcreteType>`
68 ///
69 /// Only the rest of the list (aka: from index 2) is ordered,
70 /// so we can run a binary search there if there are many types.
71 fn type_ids(&self) -> &'static [TypeIdConst];
72
73 /// **very unsafe. don't use. internal only. Horror here. go away.**
74 ///
75 /// cast `self` to a trait in the `.type_ids()` list.\
76 /// the pointer to the ref to the type in the list
77 /// is then converted to `usize`.
78 ///
79 /// panics if list length is exceeded.
80 unsafe fn cast_to(&self, trait_num: usize) -> usize;
81 /// **very unsafe. don't use. internal only. Horror here. go away.**
82 ///
83 /// cast `self` to a trait in the `.type_ids()` list.\
84 /// the pointer to the ref to the type in the list
85 /// is then converted to `usize`.
86 ///
87 /// panics if list length is exceeded.
88 unsafe fn cast_to_mut(&mut self, trait_num: usize) -> usize;
89}
90
91/// upcast from the concrete type
92/// (or from any other trait that implements `AnyTrait`) to `&dyn AnyTrait`
93///
94/// Automatically implemented on all types that implement `AnyTrait`
95pub trait AsAnyTrait: AnyTrait {
96 fn as_anytrait(&self) -> &dyn AnyTrait;
97}
98
99// everybody can have the same implementation as the `dyn Any` is always
100// the first type in the list
101impl<T: AnyTrait + ?Sized> AsAnyTrait for T {
102 fn as_anytrait(&self) -> &dyn AnyTrait {
103 unsafe {
104 let raw = self.cast_to(0);
105 union U {
106 ptr: usize,
107 a: *const *const dyn AnyTrait,
108 }
109 let tmp = U { ptr: raw };
110 return &**tmp.a;
111 }
112 }
113}
114
115impl dyn AnyTrait {
116 /// Search the list of possible traits.
117 ///
118 /// If `self` can be cast to the generic parameter,
119 /// return the index of the type in the list
120 #[inline]
121 pub fn trait_idx<T: ?Sized + 'static>(&self) -> Option<usize> {
122 let t = TypeIdConst::of::<T>();
123
124 let all_traits = self.type_ids();
125 if all_traits[0] == t {
126 return Some(0);
127 }
128 if all_traits[1] == t {
129 return Some(1);
130 }
131 let sub_traits = &all_traits[2..];
132
133 // 128: carefully chosen completely at random
134 if sub_traits.len() < 128 {
135 match sub_traits.iter().enumerate().find(|x| *x.1 == t) {
136 Some((idx, _)) => Some(2 + idx),
137 None => None,
138 }
139 } else {
140 match sub_traits.binary_search(&t) {
141 Ok(idx) => Some(2 + idx),
142 Err(_) => None,
143 }
144 }
145 }
146
147 /// Safe cast to reference to a generic type.
148 ///
149 /// Only return Some(...) if it is safe to do so.
150 #[inline]
151 pub fn downcast_ref<T: ?Sized + 'static>(&self) -> Option<&T> {
152 let Some(idx) = self.trait_idx::<T>() else {
153 return None;
154 };
155 #[allow(unsafe_code)]
156 unsafe {
157 #[allow(trivial_casts)]
158 let ta = self.cast_to(idx);
159 union UT<T: ?Sized> {
160 a: usize,
161 d: *const *const T,
162 }
163 let f = UT::<T> { a: ta };
164 let res = *f.d;
165 Some(&*res)
166 }
167 }
168
169 /// Safe cast to mutable reference to a generic type.
170 ///
171 /// Only return Some(...) if it is safe to do so.
172 #[inline]
173 pub fn downcast_mut<T: ?Sized + 'static>(&mut self) -> Option<&mut T> {
174 let Some(idx) = self.trait_idx::<T>() else {
175 return None;
176 };
177 #[allow(unsafe_code)]
178 unsafe {
179 #[allow(trivial_casts)]
180 let ta = self.cast_to_mut(idx);
181 union UT<T: ?Sized> {
182 a: usize,
183 d: *mut *mut T,
184 }
185 let f = UT::<T> { a: ta };
186 let res: *mut T = *f.d;
187 Some(&mut *res)
188 }
189 }
190}