multi_trait_object/
lib.rs1#![doc=include_str!("../README.md")]
2#[cfg(test)]
3mod tests;
4
5pub(crate) mod macros;
6mod trait_impl;
7mod std_impl;
8
9pub use trait_impl::*;
10pub use std_impl::*;
11
12use std::any::{Any, TypeId};
13use std::collections::HashMap;
14
15#[doc(hidden)]
16#[derive(Copy, Clone, Debug)]
17#[repr(C)]
18pub struct FatPointer {
19 pub data: *const (),
20 pub vptr: *const (),
21}
22
23#[allow(unused)]
24#[doc(hidden)]
25#[inline]
26pub unsafe fn null_ptr<T: Sized>(_value: &T) -> *const T {
27 std::ptr::null::<T>() as *const T
29}
30
31pub struct MultitraitObject {
47 pub(crate) data: *mut (),
48 pub(crate) original_typeid: TypeId,
49 pub(crate) traits: HashMap<TypeId, *const ()>,
50}
51
52impl MultitraitObject {
53 #[doc(hidden)]
57 pub fn new<T: 'static + Any>(value: T) -> Self {
58 let any_vtable = __fat_pointer!(T as dyn Any).vptr;
59 let data = Box::into_raw(Box::new(value)) as *mut ();
60
61 let mut this = Self {
62 data,
63 original_typeid: TypeId::of::<T>(),
64 traits: Default::default(),
65 };
66 this._register::<dyn Any>(any_vtable);
67
68 this
69 }
70
71 pub fn downcast_trait<T1: 'static + ?Sized>(&self) -> Option<&T1> {
73 if std::mem::size_of::<&T1>() != std::mem::size_of::<FatPointer>() {
74 None
75 } else {
76 unsafe {
77 self._downcast_trait::<T1>()
78 }
79 }
80 }
81
82 pub fn downcast_trait_mut<T1: 'static + ?Sized>(&mut self) -> Option<&mut T1> {
84 if std::mem::size_of::<&T1>() != std::mem::size_of::<FatPointer>() {
85 None
86 } else {
87 unsafe {
88 self._downcast_trait_mut::<T1>()
89 }
90 }
91 }
92
93 pub fn downcast_trait_boxed<T1: 'static + ?Sized>(mut self) -> Option<Box<T1>> {
95 if std::mem::size_of::<&T1>() != std::mem::size_of::<FatPointer>() {
96 None
97 } else {
98 unsafe {
99 self._downcast_boxed_trait::<T1>()
100 }
101 }
102 }
103
104 #[inline]
106 pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
107 let any = self.downcast_trait::<dyn Any>().unwrap();
108 any.downcast_ref::<T>()
109 }
110
111 #[inline]
113 pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
114 let any = self.downcast_trait_mut::<dyn Any>().unwrap();
115 any.downcast_mut::<T>()
116 }
117
118 pub fn downcast<T: Any>(self) -> Option<T> {
120 if TypeId::of::<T>() == self.original_typeid {
121 unsafe {
122 let typed_ptr = std::mem::transmute::<_, *mut T>(self.data);
124 let boxed = Box::from_raw(typed_ptr);
125
126 Some(*boxed)
127 }
128 } else {
129 None
130 }
131 }
132
133 #[inline]
137 pub fn is<T: Any>(&self) -> bool {
138 self.original_typeid == TypeId::of::<T>()
139 }
140
141 #[inline]
143 pub fn implements<T: 'static + ?Sized>(&self) -> bool {
144 self.traits.contains_key(&TypeId::of::<T>())
145 }
146
147 #[doc(hidden)]
148 #[inline]
149 pub fn _register<T2: 'static + ?Sized>(&mut self, vtable_ptr: *const ()) {
150 self.traits.insert(TypeId::of::<T2>(), vtable_ptr);
151 }
152
153 #[doc(hidden)]
154 #[inline]
155 unsafe fn _downcast_trait<T1: 'static + ?Sized>(&self) -> Option<&T1> {
156 let vptr = *self.traits.get(&TypeId::of::<T1>())?;
158 let fat_pointer = FatPointer { data: self.data, vptr };
159 let value = std::mem::transmute::<_, &&T1>(&fat_pointer);
160
161 Some(*value)
162 }
163
164 #[doc(hidden)]
165 #[inline]
166 unsafe fn _downcast_trait_mut<T1: 'static + ?Sized>(&mut self) -> Option<&mut T1> {
167 let vptr = *self.traits.get(&TypeId::of::<T1>())?;
169 let mut fat_pointer = FatPointer { data: self.data, vptr };
170 let value = std::mem::transmute::<_, &mut &mut T1>(&mut fat_pointer);
171
172 Some(*value)
173 }
174
175 #[doc(hidden)]
176 #[inline]
177 unsafe fn _downcast_boxed_trait<T1: 'static + ?Sized>(&mut self) -> Option<Box<T1>> {
178 let vptr = *self.traits.get(&TypeId::of::<T1>())?;
180 let fat_pointer = FatPointer { data: self.data, vptr };
181 let value = std::mem::transmute::<_, *const *mut T1>(&fat_pointer);
182 let value = Box::from_raw(*value);
183
184 Some(value)
185 }
186}
187
188impl Drop for MultitraitObject {
189 fn drop(&mut self) {
190 unsafe {
191 let raw = Box::from_raw(self.data);
193 std::mem::drop(raw);
194 }
195 }
196}
197
198pub trait IntoMultitrait {
199 fn into_multitrait(self) -> MultitraitObject;
200}
201
202impl<T> From<T> for MultitraitObject where T: IntoMultitrait {
203 fn from(other: T) -> Self {
204 other.into_multitrait()
205 }
206}