dyn_utils/
impls.rs

1// `dyn_object` cannot be used because `Any` has a blanket impl
2// anyway, it allows optimizing type_id as a field and not as a method
3macro_rules! any_impl {
4    ($dyn_any:ty) => {
5        const _: () = {
6            #[derive(Debug)]
7            pub struct __Vtable {
8                __drop_in_place: Option<unsafe fn(core::ptr::NonNull<()>)>,
9                __layout: core::alloc::Layout,
10                type_id: core::any::TypeId,
11            }
12
13            impl crate::object::DynTrait for $dyn_any {
14                type Vtable = __Vtable;
15                fn drop_in_place_fn(
16                    vtable: &Self::Vtable,
17                ) -> Option<unsafe fn(core::ptr::NonNull<()>)> {
18                    vtable.__drop_in_place
19                }
20                fn layout(vtable: &Self::Vtable) -> core::alloc::Layout {
21                    vtable.__layout
22                }
23            }
24
25            // SAFETY: vtable fields respect trait contract
26            unsafe impl<__Dyn: core::any::Any> crate::object::Vtable<__Dyn> for $dyn_any {
27                fn vtable<__Storage: crate::storage::Storage>() -> &'static Self::Vtable {
28                    &const {
29                        __Vtable {
30                            __drop_in_place:
31                                <Self as crate::object::Vtable<__Dyn>>::DROP_IN_PLACE_FN,
32                            __layout: core::alloc::Layout::new::<__Dyn>(),
33                            type_id: core::any::TypeId::of::<__Dyn>(),
34                        }
35                    }
36                }
37            }
38
39            impl<__Storage: crate::storage::Storage> crate::DynObject<$dyn_any, __Storage> {
40                /// Returns the [`TypeId`](core::any::TypeId) of the underlying concrete type.
41                pub fn type_id(&self) -> core::any::TypeId {
42                    self.vtable().type_id
43                }
44
45                /// Returns `true` if the inner type is the same as `T`.
46                pub fn is<T: Any>(&self) -> bool {
47                    self.type_id() == core::any::TypeId::of::<T>()
48                }
49
50                /// Returns some reference to the inner value if it is of type `T`,
51                /// or `None` if it isn’t.
52                pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
53                    // SAFETY: `is` ensures that the storage has been initialized with `T`
54                    self.is::<T>().then(|| unsafe { self.storage().as_ref() })
55                }
56
57                /// Returns some mutable reference to the inner value if it is of type `T`,
58                /// or `None` if it isn’t.
59                pub fn downcast_mut<T: Any>(&mut self) -> Option<&mut T> {
60                    self.is::<T>()
61                        // SAFETY: `is` ensures that the storage has been initialized with `T`
62                        .then(|| unsafe { self.storage_mut().as_mut() })
63                }
64
65                /// Attempts to downcast the object to a concrete type.
66                // TODO understand why it prevents 100% coverage
67                #[cfg_attr(coverage_nightly, coverage(off))]
68                pub fn downcast<T: Any>(self) -> Result<T, Self> {
69                    if self.is::<T>() {
70                        let mut this = core::mem::ManuallyDrop::new(self);
71                        let storage = this.storage_mut();
72                        // SAFETY: `is` ensures that the storage has been initialized with `T`
73                        let obj = unsafe { storage.ptr_mut().cast().read() };
74                        // SAFETY: the storage is no longer used after,
75                        // and `is` ensures that the storage has been initialized with `T`
76                        unsafe {
77                            __Storage::drop_in_place(storage, core::alloc::Layout::new::<T>())
78                        };
79                        Ok(obj)
80                    } else {
81                        Err(self)
82                    }
83                }
84            }
85        };
86    };
87}
88pub(crate) use any_impl;
89
90#[cfg(test)]
91macro_rules! any_test {
92    ($test:ident, $dyn_any:ty) => {
93        #[test]
94        fn $test() {
95            struct Droppable;
96            impl Drop for Droppable {
97                fn drop(&mut self) {}
98            }
99            let mut any = crate::DynObject::<dyn Any>::new(false);
100            assert_eq!(any.downcast_ref::<()>(), None);
101            assert_eq!(any.downcast_ref::<bool>(), Some(&false));
102            assert_eq!(any.downcast_mut::<()>(), None);
103            *any.downcast_mut::<bool>().unwrap() = true;
104            let storage = any.downcast::<()>().unwrap_err();
105            assert!(storage.downcast::<bool>().unwrap());
106            drop(crate::DynObject::<dyn Any>::new(()));
107            drop(crate::DynObject::<dyn Any>::new(Droppable));
108            #[cfg(feature = "alloc")]
109            let _ = crate::DynObject::<dyn Any, crate::storage::Box>::new(false).downcast::<bool>();
110        }
111    };
112}
113#[cfg(test)]
114pub(crate) use any_test;
115
116const _: () = {
117    #[derive(Debug)]
118    pub struct __Vtable {
119        __drop_in_place: Option<unsafe fn(::core::ptr::NonNull<()>)>,
120        __layout: ::core::alloc::Layout,
121        poll: unsafe fn(),
122    }
123    impl<'__lt, __TypeOutput> crate::object::DynTrait for dyn Future<Output = __TypeOutput> + '__lt {
124        type Vtable = __Vtable;
125        fn drop_in_place_fn(vtable: &Self::Vtable) -> Option<unsafe fn(core::ptr::NonNull<()>)> {
126            vtable.__drop_in_place
127        }
128        fn layout(vtable: &Self::Vtable) -> core::alloc::Layout {
129            vtable.__layout
130        }
131    }
132    // SAFETY: vtable fields respect trait contract
133    unsafe impl<'__lt, __TypeOutput, __Dyn: Future<Output = __TypeOutput> + '__lt>
134        crate::object::Vtable<__Dyn> for dyn Future<Output = __TypeOutput> + '__lt
135    {
136        fn vtable<__Storage: crate::storage::Storage>() -> &'static Self::Vtable {
137            &const {
138                __Vtable {
139                    __drop_in_place: <Self as crate::object::Vtable<__Dyn>>::DROP_IN_PLACE_FN,
140                    __layout: core::alloc::Layout::new::<__Dyn>(),
141                    #[allow(
142                        clippy::missing_transmute_annotations,
143                        clippy::useless_transmute
144                    )]
145                    // SAFETY: transmutation are only used to erase lifetime,
146                    // the real lifetime being enforced in the trait implementation
147                    poll: unsafe {
148                        ::core::mem::transmute::<
149                            fn(
150                                ::core::pin::Pin<&mut __Storage>,
151                                &mut core::task::Context<'_>,
152                            ) -> core::task::Poll<__Dyn::Output>,
153                            unsafe fn(),
154                        >(|__self, cx| {
155                            ::core::mem::transmute(__Dyn::poll(
156                                __self.as_pinned_mut(),
157                                ::core::mem::transmute(cx),
158                            ))
159                        })
160                    },
161                }
162            }
163        }
164    }
165    impl<'__lt, __TypeOutput, __Storage: crate::storage::Storage> Future
166        for crate::DynObject<dyn Future<Output = __TypeOutput> + '__lt, __Storage>
167    {
168        type Output = __TypeOutput;
169        fn poll(
170            self: core::pin::Pin<&mut Self>,
171            cx: &mut core::task::Context<'_>,
172        ) -> core::task::Poll<Self::Output> {
173            // SAFETY: the vtable method has been initialized with the given type
174            unsafe {
175                ::core::mem::transmute::<
176                    unsafe fn(),
177                    fn(
178                        ::core::pin::Pin<&mut __Storage>,
179                        &mut core::task::Context<'_>,
180                    ) -> core::task::Poll<Self::Output>,
181                >(self.vtable().poll)(self.storage_pinned_mut(), cx)
182            }
183        }
184    }
185};
186const _: () = {
187    #[derive(Debug)]
188    pub struct __Vtable {
189        __drop_in_place: Option<unsafe fn(::core::ptr::NonNull<()>)>,
190        __layout: ::core::alloc::Layout,
191        poll: unsafe fn(),
192    }
193    impl<'__lt, __TypeOutput> crate::object::DynTrait
194        for dyn Future<Output = __TypeOutput> + '__lt + Send
195    {
196        type Vtable = __Vtable;
197        fn drop_in_place_fn(vtable: &Self::Vtable) -> Option<unsafe fn(core::ptr::NonNull<()>)> {
198            vtable.__drop_in_place
199        }
200        fn layout(vtable: &Self::Vtable) -> core::alloc::Layout {
201            vtable.__layout
202        }
203    }
204    // SAFETY: vtable fields respect trait contract
205    unsafe impl<'__lt, __TypeOutput, __Dyn: Future<Output = __TypeOutput> + '__lt + Send>
206        crate::object::Vtable<__Dyn> for dyn Future<Output = __TypeOutput> + '__lt + Send
207    {
208        fn vtable<__Storage: crate::storage::Storage>() -> &'static Self::Vtable {
209            &const {
210                __Vtable {
211                    __drop_in_place: <Self as crate::object::Vtable<__Dyn>>::DROP_IN_PLACE_FN,
212                    __layout: core::alloc::Layout::new::<__Dyn>(),
213                    #[allow(
214                        clippy::missing_transmute_annotations,
215                        clippy::useless_transmute
216                    )]
217                    // SAFETY: transmutation are only used to erase lifetime,
218                    // the real lifetime being enforced in the trait implementation
219                    poll: unsafe {
220                        ::core::mem::transmute::<
221                            fn(
222                                ::core::pin::Pin<&mut __Storage>,
223                                &mut core::task::Context<'_>,
224                            ) -> core::task::Poll<__Dyn::Output>,
225                            unsafe fn(),
226                        >(|__self, cx| {
227                            ::core::mem::transmute(__Dyn::poll(
228                                __self.as_pinned_mut(),
229                                ::core::mem::transmute(cx),
230                            ))
231                        })
232                    },
233                }
234            }
235        }
236    }
237    impl<'__lt, __TypeOutput, __Storage: crate::storage::Storage> Future
238        for crate::DynObject<dyn Future<Output = __TypeOutput> + '__lt + Send, __Storage>
239    {
240        type Output = __TypeOutput;
241        fn poll(
242            self: core::pin::Pin<&mut Self>,
243            cx: &mut core::task::Context<'_>,
244        ) -> core::task::Poll<Self::Output> {
245            // SAFETY: the vtable method has been initialized with the given type
246            unsafe {
247                ::core::mem::transmute::<
248                    unsafe fn(),
249                    fn(
250                        ::core::pin::Pin<&mut __Storage>,
251                        &mut core::task::Context<'_>,
252                    ) -> core::task::Poll<Self::Output>,
253                >(self.vtable().poll)(self.storage_pinned_mut(), cx)
254            }
255        }
256    }
257};
258
259const _: () = {
260    #[derive(Debug)]
261    pub struct __Vtable {
262        __drop_in_place: Option<unsafe fn(::core::ptr::NonNull<()>)>,
263        __layout: ::core::alloc::Layout,
264        next: unsafe fn(),
265        size_hint: unsafe fn(),
266        nth: unsafe fn(),
267    }
268    impl<'__lt, __TypeItem> crate::object::DynTrait for dyn Iterator<Item = __TypeItem> + '__lt {
269        type Vtable = __Vtable;
270        fn drop_in_place_fn(vtable: &Self::Vtable) -> Option<unsafe fn(core::ptr::NonNull<()>)> {
271            vtable.__drop_in_place
272        }
273        fn layout(vtable: &Self::Vtable) -> core::alloc::Layout {
274            vtable.__layout
275        }
276    }
277    // SAFETY: vtable fields respect trait contract
278    unsafe impl<'__lt, __TypeItem, __Dyn: Iterator<Item = __TypeItem> + '__lt>
279        crate::object::Vtable<__Dyn> for dyn Iterator<Item = __TypeItem> + '__lt
280    {
281        fn vtable<__Storage: crate::storage::Storage>() -> &'static Self::Vtable {
282            &const {
283                __Vtable {
284                    __drop_in_place: <Self as crate::object::Vtable<__Dyn>>::DROP_IN_PLACE_FN,
285                    __layout: core::alloc::Layout::new::<__Dyn>(),
286                    #[allow(
287                        clippy::missing_transmute_annotations,
288                        clippy::useless_transmute
289                    )]
290                    // SAFETY: transmutation are only used to erase lifetime,
291                    // the real lifetime being enforced in the trait implementation
292                    next: unsafe {
293                        ::core::mem::transmute::<
294                            fn(&mut __Storage) -> Option<__Dyn::Item>,
295                            unsafe fn(),
296                        >(|__self| {
297                            ::core::mem::transmute(__Dyn::next(__self.as_mut()))
298                        })
299                    },
300                    #[allow(
301                        clippy::missing_transmute_annotations,
302                        clippy::useless_transmute
303                    )]
304                    // SAFETY: transmutation are only used to erase lifetime,
305                    // the real lifetime being enforced in the trait implementation
306                    size_hint: unsafe {
307                        ::core::mem::transmute::<
308                            fn(&__Storage) -> (usize, Option<usize>),
309                            unsafe fn(),
310                        >(|__self| {
311                            ::core::mem::transmute(__Dyn::size_hint(__self.as_ref()))
312                        })
313                    },
314                    #[allow(
315                        clippy::missing_transmute_annotations,
316                        clippy::useless_transmute
317                    )]
318                    // SAFETY: transmutation are only used to erase lifetime,
319                    // the real lifetime being enforced in the trait implementation
320                    nth: unsafe {
321                        ::core::mem::transmute::<
322                            fn(&mut __Storage, usize) -> Option<__Dyn::Item>,
323                            unsafe fn(),
324                        >(|__self, n| {
325                            ::core::mem::transmute(__Dyn::nth(
326                                __self.as_mut(),
327                                ::core::mem::transmute(n),
328                            ))
329                        })
330                    },
331                }
332            }
333        }
334    }
335    impl<'__lt, __TypeItem, __Storage: crate::storage::Storage> Iterator
336        for crate::DynObject<dyn Iterator<Item = __TypeItem> + '__lt, __Storage>
337    {
338        type Item = __TypeItem;
339        fn next(&mut self) -> Option<Self::Item> {
340            // SAFETY: the vtable method has been initialized with the given type
341            unsafe {
342                ::core::mem::transmute::<unsafe fn(), fn(&mut __Storage) -> Option<Self::Item>>(
343                    self.vtable().next,
344                )(self.storage_mut())
345            }
346        }
347        fn size_hint(&self) -> (usize, Option<usize>) {
348            // SAFETY: the vtable method has been initialized with the given type
349            unsafe {
350                ::core::mem::transmute::<unsafe fn(), fn(&__Storage) -> (usize, Option<usize>)>(
351                    self.vtable().size_hint,
352                )(self.storage())
353            }
354        }
355        fn nth(&mut self, n: usize) -> Option<Self::Item> {
356            // SAFETY: the vtable method has been initialized with the given type
357            unsafe {
358                ::core::mem::transmute::<unsafe fn(), fn(&mut __Storage, usize) -> Option<Self::Item>>(
359                    self.vtable().nth,
360                )(self.storage_mut(), n)
361            }
362        }
363    }
364};
365
366#[cfg_attr(coverage_nightly, coverage(off))]
367#[cfg(test)]
368mod tests {
369    use futures::FutureExt;
370
371    use crate::DynObject;
372
373    fn assert_send<T: Send>(_: &T) {}
374
375    #[test]
376    fn dyn_future() {
377        let n = 42;
378        let future = DynObject::<dyn Future<Output = usize>>::new(async { n });
379        assert_eq!(future.now_or_never(), Some(42));
380    }
381
382    #[test]
383    fn dyn_future_send() {
384        let n = 42;
385        let future = DynObject::<dyn Future<Output = usize> + Send>::new(async { n });
386        assert_send(&future);
387        assert_eq!(future.now_or_never(), Some(42));
388    }
389
390    #[test]
391    fn dyn_iterator() {
392        let mut iter = DynObject::<dyn Iterator<Item = usize>>::new([0, 1, 2, 3].into_iter());
393        assert_eq!(iter.size_hint(), (4, Some(4)));
394        assert_eq!(iter.nth(2), Some(2));
395        assert_eq!(iter.next(), Some(3));
396    }
397}