1use core::{alloc::Layout, any::Any, fmt, marker::PhantomData, mem, pin::Pin, ptr::NonNull};
3
4use crate::{
5 impls::any_impl,
6 storage::{DefaultStorage, Storage},
7};
8
9pub struct DynObject<Dyn: DynTrait + ?Sized, S: Storage = DefaultStorage> {
25 storage: S,
26 vtable: &'static Dyn::Vtable,
27 _phantom: PhantomData<Dyn>,
28}
29
30unsafe impl<Dyn: Send + DynTrait + ?Sized, S: Storage> Send for DynObject<Dyn, S> {}
32
33unsafe impl<Dyn: Sync + DynTrait + ?Sized, S: Storage> Sync for DynObject<Dyn, S> {}
35
36impl<Dyn: Unpin + DynTrait + ?Sized, S: Storage> Unpin for DynObject<Dyn, S> {}
37
38impl<S: Storage, Dyn: DynTrait + ?Sized> DynObject<Dyn, S> {
39 pub fn new<T>(object: T) -> Self
41 where
42 Dyn: Vtable<T>,
43 {
44 Self {
45 storage: S::new(object),
46 vtable: Dyn::vtable::<S>(),
47 _phantom: PhantomData,
48 }
49 }
50
51 #[cfg(feature = "alloc")]
53 pub fn from_box<T>(boxed: alloc::boxed::Box<T>) -> Self
54 where
55 S: crate::storage::FromBox,
56 Dyn: Vtable<T>,
57 {
58 Self {
59 storage: S::from_box(boxed),
60 vtable: Dyn::vtable::<S>(),
61 _phantom: PhantomData,
62 }
63 }
64
65 #[doc(hidden)]
66 pub fn vtable(&self) -> &'static Dyn::Vtable {
67 self.vtable
68 }
69
70 #[doc(hidden)]
71 pub fn storage(&self) -> &S {
72 &self.storage
73 }
74
75 #[doc(hidden)]
76 pub fn storage_mut(&mut self) -> &mut S {
77 &mut self.storage
78 }
79
80 #[doc(hidden)]
81 pub fn storage_pinned_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
82 unsafe { self.map_unchecked_mut(|this| &mut this.storage) }
84 }
85
86 #[doc(hidden)]
87 pub fn insert<T>(this: &mut Option<Self>, object: T) -> &mut T
88 where
89 Dyn: Vtable<T>,
90 {
91 let storage = this.insert(DynObject::new(object));
92 unsafe { storage.storage_mut().as_mut::<T>() }
94 }
95
96 #[doc(hidden)]
97 pub fn insert_pinned<T>(this: Pin<&mut Option<Self>>, object: T) -> Pin<&mut T>
98 where
99 Dyn: Vtable<T>,
100 {
101 unsafe { this.map_unchecked_mut(|opt| Self::insert(opt, object)) }
103 }
104}
105
106impl<Dyn: DynTrait + ?Sized, S: Storage> Drop for DynObject<Dyn, S> {
107 fn drop(&mut self) {
108 if let Some(drop_inner) = Dyn::drop_in_place_fn(self.vtable) {
109 unsafe { drop_inner(self.storage.ptr_mut()) };
112 }
113 let layout = Dyn::layout(self.vtable);
114 unsafe { self.storage.drop_in_place(layout) };
117 }
118}
119
120#[cfg_attr(coverage_nightly, coverage(off))]
121impl<Dyn: DynTrait<Vtable: fmt::Debug> + ?Sized, S: Storage + fmt::Debug> fmt::Debug
122 for DynObject<Dyn, S>
123{
124 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
125 f.debug_struct("DynObject")
126 .field("inner", &self.storage)
127 .field("vtable", &self.vtable)
128 .finish()
129 }
130}
131any_impl!(dyn Any);
134any_impl!(dyn Any + Send);
135any_impl!(dyn Any + Send + Sync);
136
137pub trait DynTrait {
139 type Vtable: 'static;
141 fn drop_in_place_fn(vtable: &Self::Vtable) -> Option<unsafe fn(NonNull<()>)>;
143 fn layout(vtable: &Self::Vtable) -> Layout;
145}
146
147pub unsafe trait Vtable<T>: DynTrait {
155 fn vtable<S: Storage>() -> &'static Self::Vtable;
157 const DROP_IN_PLACE_FN: Option<unsafe fn(NonNull<()>)> = if mem::needs_drop::<T>() {
159 Some(|ptr_mut| unsafe { ptr_mut.cast::<T>().drop_in_place() })
161 } else {
162 None
163 };
164}
165
166#[cfg(test)]
167mod tests {
168 use crate::{impls::any_test, object::Any};
169
170 any_test!(dyn_any, dyn Any);
171 any_test!(dyn_any_send, dyn Any + Send);
172 any_test!(dyn_any_send_sync, dyn Any + Send + Sync);
173}