1use crate::cast_target::DynDynCastTarget;
2use cfg_if::cfg_if;
3use core::any::TypeId;
4use core::fmt::{self, Debug};
5use core::marker::Unsize;
6use core::mem;
7use core::ptr::{self, DynMetadata, Pointee};
8
9#[cfg(doc)]
10use crate::dyn_dyn_cast;
11
12#[derive(Debug, Clone, Copy)]
14pub struct AnyDynMetadata(*const ());
15
16impl AnyDynMetadata {
17 pub const fn upcast<T: ?Sized>(meta: DynMetadata<T>) -> AnyDynMetadata {
19 unsafe { AnyDynMetadata(mem::transmute::<DynMetadata<T>, *const ()>(meta)) }
24 }
25
26 pub const unsafe fn downcast<T: DynDynCastTarget + ?Sized>(self) -> DynMetadata<T> {
32 unsafe { mem::transmute::<*const (), DynMetadata<T>>(self.0) }
35 }
36}
37
38impl<T: ?Sized> From<DynMetadata<T>> for AnyDynMetadata {
39 fn from(meta: DynMetadata<T>) -> Self {
40 AnyDynMetadata::upcast(meta)
41 }
42}
43
44unsafe impl Send for AnyDynMetadata {}
46
47unsafe impl Sync for AnyDynMetadata {}
49
50cfg_if! {
51 if #[cfg(feature = "dynamic-names")] {
52 type TypeName = &'static str;
53
54 const fn type_name<T: ?Sized>() -> TypeName {
55 core::any::type_name::<T>()
56 }
57 } else {
58 #[derive(Debug, Clone, Copy)]
59 struct TypeName;
60
61 #[allow(clippy::extra_unused_type_parameters)]
62 const fn type_name<T: ?Sized>() -> TypeName { TypeName }
63 }
64}
65
66#[derive(Debug, Clone, Copy)]
67struct DynInfo(TypeId, TypeName);
68
69impl DynInfo {
70 pub const fn of<T: 'static + ?Sized>() -> DynInfo {
71 DynInfo(TypeId::of::<T>(), type_name::<T>())
72 }
73
74 pub fn type_id(self) -> TypeId {
75 self.0
76 }
77
78 #[cfg(feature = "dynamic-names")]
79 pub fn name(self) -> &'static str {
80 self.1
81 }
82}
83
84impl PartialEq for DynInfo {
85 fn eq(&self, other: &Self) -> bool {
86 self.0 == other.0
87 }
88}
89
90impl Eq for DynInfo {}
91
92pub struct DynDynTableEntry {
98 ty: DynInfo,
99 meta: AnyDynMetadata,
100}
101
102impl DynDynTableEntry {
103 const fn meta_for_ty<
104 T: Unsize<D>,
105 D: ?Sized + Pointee<Metadata = DynMetadata<M>>,
106 M: ?Sized,
107 >() -> DynMetadata<M> {
108 ptr::metadata(ptr::null::<T>() as *const D)
109 }
110
111 #[doc(hidden)]
112 pub const fn new<
113 T: Unsize<D>,
114 D: ?Sized + Pointee<Metadata = DynMetadata<M>> + 'static,
115 M: ?Sized,
116 >() -> DynDynTableEntry {
117 DynDynTableEntry {
118 ty: DynInfo::of::<D>(),
119 meta: AnyDynMetadata::upcast(Self::meta_for_ty::<T, D, M>()),
120 }
121 }
122
123 pub fn type_id(&self) -> TypeId {
125 self.ty.type_id()
126 }
127
128 #[cfg(feature = "dynamic-names")]
130 pub fn type_name(&self) -> &'static str {
131 self.ty.name()
132 }
133}
134
135impl Debug for DynDynTableEntry {
136 #[cfg(feature = "dynamic-names")]
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 write!(
139 f,
140 "DynDynTableEntry(<{}>: {:?})",
141 self.type_name(),
142 self.meta
143 )
144 }
145
146 #[cfg(not(feature = "dynamic-names"))]
147 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
148 write!(f, "DynDynTableEntry({:?}: {:?})", self.type_id(), self.meta)
149 }
150}
151
152#[derive(Debug, Clone, Copy)]
154pub struct DynDynTable {
155 traits: &'static [DynDynTableEntry],
156}
157
158impl DynDynTable {
159 pub fn find_untyped(&self, type_id: TypeId) -> Option<AnyDynMetadata> {
161 self.traits
162 .iter()
163 .find(|&entry| entry.ty.type_id() == type_id)
164 .map(|entry| entry.meta)
165 }
166
167 pub fn find<D: ?Sized + DynDynCastTarget + 'static>(&self) -> Option<DynMetadata<D>> {
169 self.find_untyped(TypeId::of::<D>()).map(|meta| {
170 unsafe { meta.downcast() }
172 })
173 }
174
175 pub fn into_slice(self) -> &'static [DynDynTableEntry] {
177 self.traits
178 }
179
180 #[doc(hidden)]
181 pub const fn new(traits: &'static [DynDynTableEntry]) -> DynDynTable {
182 DynDynTable { traits }
183 }
184}
185
186impl IntoIterator for DynDynTable {
187 type Item = &'static DynDynTableEntry;
188 type IntoIter = DynDynTableIterator;
189
190 fn into_iter(self) -> Self::IntoIter {
191 DynDynTableIterator(self.traits.iter())
192 }
193}
194
195pub struct DynDynTableIterator(core::slice::Iter<'static, DynDynTableEntry>);
197
198impl Iterator for DynDynTableIterator {
199 type Item = &'static DynDynTableEntry;
200
201 fn next(&mut self) -> Option<Self::Item> {
202 self.0.next()
203 }
204}