abi_stable/sabi_trait/robject.rs
1use super::*;
2
3use std::fmt;
4
5#[allow(unused_imports)]
6use core_extensions::SelfOps;
7
8use crate::{
9 abi_stability::PrefixStableAbi,
10 erased_types::{c_functions::adapt_std_fmt, InterfaceType, MakeRequiredTraits},
11 pointer_trait::{
12 AsMutPtr, AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference, PK_SmartPointer,
13 PointerKind, TransmuteElement,
14 },
15 sabi_trait::vtable::{BaseVtable_Prefix, BaseVtable_Ref},
16 sabi_types::{MaybeCmp, RMut, RRef},
17 std_types::UTypeId,
18 type_level::{
19 impl_enum::{Implemented, Unimplemented},
20 trait_marker,
21 },
22 StableAbi,
23};
24
25/// `RObject` implements ffi-safe trait objects, for a minimal selection of traits.
26///
27/// The main use of `RObject<_>` is as the default backend for `#[sabi_trait]`
28/// generated trait objects.
29///
30/// # Construction
31///
32/// `RObject<_>` is how `#[sabi_trait]`-based ffi-safe trait objects are implemented,
33/// and there's no way to construct it separate from those.
34///
35/// # Trait object
36///
37/// `RObject<'borrow, Pointer<()>, Interface, VTable>`
38/// can be used as a trait object for any combination of
39/// the traits listed below:
40///
41/// - [`Send`]
42///
43/// - [`Sync`]
44///
45/// - [`Unpin`](std::marker::Unpin)
46///
47/// - [`Debug`]
48///
49/// - [`Display`]
50///
51/// - [`Error`](std::error::Error)
52///
53/// - [`Clone`]
54///
55/// # Deconstruction
56///
57/// `RObject<_>` can be unwrapped into a concrete type,
58/// within the same dynamic library/executable that constructed it,
59/// using these (fallible) conversion methods:
60///
61/// - [`downcast_into`](#method.downcast_into):
62/// Unwraps into a pointer to `T`.Requires `T: 'static`.
63///
64/// - [`downcast_as`](#method.downcast_as):
65/// Unwraps into a `&T`.Requires `T: 'static`.
66///
67/// - [`downcast_as_mut`](#method.downcast_as_mut):
68/// Unwraps into a `&mut T`.Requires `T: 'static`.
69///
70/// `RObject` can only be converted back if the trait object was constructed to allow it.
71///
72///
73///
74///
75///
76#[repr(C)]
77#[derive(StableAbi)]
78#[sabi(
79 not_stableabi(V),
80 bound(V: PrefixStableAbi),
81 bound(I: InterfaceType),
82 extra_checks = <I as MakeRequiredTraits>::MAKE,
83)]
84pub struct RObject<'lt, P, I, V>
85where
86 P: GetPointerKind,
87{
88 vtable: PrefixRef<V>,
89 ptr: ManuallyDrop<P>,
90 _marker: PhantomData<(&'lt (), extern "C" fn() -> I)>,
91}
92
93mod clone_impl {
94 pub trait CloneImpl<PtrKind> {
95 fn clone_impl(&self) -> Self;
96 }
97}
98use self::clone_impl::CloneImpl;
99
100/// This impl is for smart pointers.
101impl<'lt, P, I, V> CloneImpl<PK_SmartPointer> for RObject<'lt, P, I, V>
102where
103 P: AsPtr,
104 I: InterfaceType<Clone = Implemented<trait_marker::Clone>>,
105{
106 fn clone_impl(&self) -> Self {
107 let ptr =
108 unsafe { self.sabi_robject_vtable()._sabi_clone().unwrap()(RRef::new(&self.ptr)) };
109 Self {
110 vtable: self.vtable,
111 ptr: ManuallyDrop::new(ptr),
112 _marker: PhantomData,
113 }
114 }
115}
116
117/// This impl is for references.
118impl<'lt, P, I, V> CloneImpl<PK_Reference> for RObject<'lt, P, I, V>
119where
120 P: AsPtr + Copy,
121 I: InterfaceType,
122{
123 fn clone_impl(&self) -> Self {
124 Self {
125 vtable: self.vtable,
126 ptr: ManuallyDrop::new(*self.ptr),
127 _marker: PhantomData,
128 }
129 }
130}
131
132/// Clone is implemented for references and smart pointers,
133/// using `GetPointerKind` to decide whether `P` is a smart pointer or a reference.
134///
135/// RObject does not implement Clone if `P` == `&mut ()` :
136///
137///
138/// ```compile_fail
139/// use abi_stable::{
140/// sabi_trait::{doc_examples::ConstExample_TO, TD_Opaque},
141/// std_types::*,
142/// };
143///
144/// let mut object = ConstExample_TO::from_value(10usize, TD_Opaque);
145/// let borrow = object.sabi_reborrow_mut();
146/// let _ = borrow.clone();
147/// ```
148///
149/// Here is the same example with `sabi_reborrow`
150///
151/// ```
152/// use abi_stable::{
153/// sabi_trait::{doc_examples::ConstExample_TO, TD_Opaque},
154/// std_types::*,
155/// };
156///
157/// let mut object = ConstExample_TO::from_value(10usize, TD_Opaque);
158/// let borrow = object.sabi_reborrow();
159/// let _ = borrow.clone();
160/// ```
161///
162///
163impl<'lt, P, I, V> Clone for RObject<'lt, P, I, V>
164where
165 P: AsPtr,
166 I: InterfaceType,
167 Self: CloneImpl<<P as GetPointerKind>::Kind>,
168{
169 fn clone(&self) -> Self {
170 self.clone_impl()
171 }
172}
173
174impl<'lt, P, I, V> Debug for RObject<'lt, P, I, V>
175where
176 P: AsPtr<PtrTarget = ()> + AsPtr,
177 I: InterfaceType<Debug = Implemented<trait_marker::Debug>>,
178{
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 unsafe {
181 adapt_std_fmt::<ErasedObject>(
182 self.sabi_erased_ref(),
183 self.sabi_robject_vtable()._sabi_debug().unwrap(),
184 f,
185 )
186 }
187 }
188}
189
190impl<'lt, P, I, V> Display for RObject<'lt, P, I, V>
191where
192 P: AsPtr<PtrTarget = ()>,
193 I: InterfaceType<Display = Implemented<trait_marker::Display>>,
194{
195 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196 unsafe {
197 adapt_std_fmt::<ErasedObject>(
198 self.sabi_erased_ref(),
199 self.sabi_robject_vtable()._sabi_display().unwrap(),
200 f,
201 )
202 }
203 }
204}
205
206impl<'lt, P, I, V> std::error::Error for RObject<'lt, P, I, V>
207where
208 P: AsPtr<PtrTarget = ()>,
209 I: InterfaceType<
210 Display = Implemented<trait_marker::Display>,
211 Debug = Implemented<trait_marker::Debug>,
212 Error = Implemented<trait_marker::Error>,
213 >,
214{
215}
216
217unsafe impl<'lt, P, I, V> Send for RObject<'lt, P, I, V>
218where
219 P: GetPointerKind,
220 I: InterfaceType<Send = Implemented<trait_marker::Send>>,
221{
222}
223
224unsafe impl<'lt, P, I, V> Sync for RObject<'lt, P, I, V>
225where
226 P: GetPointerKind,
227 I: InterfaceType<Sync = Implemented<trait_marker::Sync>>,
228{
229}
230
231impl<'lt, P, I, V> Unpin for RObject<'lt, P, I, V>
232where
233 // `Unpin` is a property of the referent
234 P: GetPointerKind,
235 I: InterfaceType<Unpin = Implemented<trait_marker::Unpin>>,
236{
237}
238
239impl<'lt, P, I, V> RObject<'lt, P, I, V>
240where
241 P: AsPtr<PtrTarget = ()>,
242{
243 /// Constructs an RObject from a pointer and an extra vtable.
244 ///
245 /// This is mostly intended to be called by `#[sabi_trait]` generated trait objects.
246 ///
247 /// # Safety
248 ///
249 /// These are the requirements for the caller:
250 ///
251 /// - `P` must be a pointer to the type that the vtable functions
252 /// take as the first parameter.
253 ///
254 /// - The vtable must not come from a reborrowed `RObject`
255 /// (created using `RObject::reborrow` or `RObject::reborrow_mut`).
256 ///
257 /// - The vtable must be the `SomeVTableName` of a struct declared with
258 /// `#[derive(StableAbi)] #[sabi(kind(Prefix(prefix_ref= SomeVTableName)))]`.
259 ///
260 /// - The vtable must have `RObjectVtable_Ref` as its first declared field
261 ///
262 pub unsafe fn with_vtable<OrigPtr>(ptr: OrigPtr, vtable: PrefixRef<V>) -> RObject<'lt, P, I, V>
263 where
264 OrigPtr: CanTransmuteElement<(), TransmutedPtr = P>,
265 OrigPtr::PtrTarget: Sized + 'lt,
266 P: AsPtr<PtrTarget = ()>,
267 {
268 RObject {
269 vtable,
270 ptr: ManuallyDrop::new(unsafe { ptr.transmute_element::<()>() }),
271 _marker: PhantomData,
272 }
273 }
274}
275
276impl<'borr, 'a, I, V> RObject<'borr, RRef<'a, ()>, I, V> {
277 /// This function allows constructing an RObject in a constant/static.
278 ///
279 /// This is mostly intended for `#[sabi_trait]`-generated trait objects
280 ///
281 /// # Safety
282 ///
283 /// This has the same safety requirements as `RObject::with_vtable`
284 ///
285 /// # Example
286 ///
287 /// Because this is intended for `#[sabi_trait]` generated trait objects,
288 /// this demonstrates how to construct one in a constant.
289 ///
290 /// ```
291 /// use abi_stable::sabi_trait::{
292 /// doc_examples::ConstExample_CTO,
293 /// prelude::TD_Opaque,
294 /// };
295 ///
296 /// const EXAMPLE0: ConstExample_CTO<'static, 'static> =
297 /// ConstExample_CTO::from_const(&0usize, TD_Opaque);
298 ///
299 /// ```
300 pub const unsafe fn with_vtable_const<T, Downcasting>(ptr: &'a T, vtable: PrefixRef<V>) -> Self
301 where
302 T: 'borr,
303 {
304 RObject {
305 vtable,
306 ptr: {
307 let x = unsafe { RRef::new(ptr).transmute::<()>() };
308 ManuallyDrop::new(x)
309 },
310 _marker: PhantomData,
311 }
312 }
313}
314
315impl<'lt, P, I, V> RObject<'lt, P, I, V>
316where
317 P: GetPointerKind,
318{
319 /// The uid in the vtable has to be the same as the one for T,
320 /// otherwise it was not created from that T in the library that
321 /// declared the trait object.
322 fn sabi_check_same_utypeid<T>(&self) -> Result<(), UneraseError<()>>
323 where
324 T: 'static,
325 {
326 let expected_typeid = self.sabi_robject_vtable()._sabi_type_id()();
327 let actual_typeid = UTypeId::new::<T>();
328 if expected_typeid == MaybeCmp::Just(actual_typeid) {
329 Ok(())
330 } else {
331 Err(UneraseError {
332 robject: (),
333 expected_typeid,
334 actual_typeid,
335 })
336 }
337 }
338
339 /// Attempts to unerase this trait object into the pointer it was constructed with.
340 ///
341 /// # Errors
342 ///
343 /// This will return an error in any of these conditions:
344 ///
345 /// - It is called in a dynamic library/binary outside
346 /// the one from which this RObject was constructed.
347 ///
348 /// - The trait object wrapping this `RObject` was constructed with a
349 /// `TD_CanDowncast` argument.
350 ///
351 /// - `T` is not the concrete type this `RObject<_>` was constructed with.
352 ///
353 /// # Example
354 ///
355 /// ```rust
356 /// use abi_stable::{
357 /// sabi_trait::doc_examples::Doer_TO, std_types::RBox,
358 /// type_level::downcasting::TD_CanDowncast,
359 /// };
360 ///
361 /// let to = || Doer_TO::from_value(5usize, TD_CanDowncast);
362 ///
363 /// // `to.obj` is an RObject
364 /// assert_eq!(
365 /// to().obj.downcast_into::<usize>().ok(),
366 /// Some(RBox::new(5usize))
367 /// );
368 /// assert_eq!(to().obj.downcast_into::<u8>().ok(), None);
369 ///
370 /// ```
371 pub fn downcast_into<T>(self) -> Result<P::TransmutedPtr, UneraseError<Self>>
372 where
373 T: 'static,
374 P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
375 {
376 check_unerased!(self, self.sabi_check_same_utypeid::<T>());
377 unsafe {
378 let this = ManuallyDrop::new(self);
379 Ok(ptr::read(&*this.ptr).transmute_element::<T>())
380 }
381 }
382
383 /// Attempts to unerase this trait object into a reference of
384 /// the value was constructed with.
385 ///
386 /// # Errors
387 ///
388 /// This will return an error in any of these conditions:
389 ///
390 /// - It is called in a dynamic library/binary outside
391 /// the one from which this RObject was constructed.
392 ///
393 /// - The trait object wrapping this `RObject` was constructed with a
394 /// `TD_CanDowncast` argument.
395 ///
396 /// - `T` is not the concrete type this `RObject<_>` was constructed with.
397 ///
398 /// # Example
399 ///
400 /// ```rust
401 /// use abi_stable::{
402 /// sabi_trait::doc_examples::Doer_TO, std_types::RArc,
403 /// type_level::downcasting::TD_CanDowncast, RMut, RRef,
404 /// };
405 ///
406 /// {
407 /// let to: Doer_TO<'_, RArc<()>> =
408 /// Doer_TO::from_ptr(RArc::new(8usize), TD_CanDowncast);
409 ///
410 /// // `to.obj` is an RObject
411 /// assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&8usize));
412 /// assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
413 /// }
414 /// {
415 /// // `#[sabi_trait]` trait objects constructed from `&`
416 /// // use `RRef<'_, ()>` instead of `&'_ ()`
417 /// // since `&T` can't soundly be transmuted back and forth into `&()`
418 /// let to: Doer_TO<'_, RRef<'_, ()>> = Doer_TO::from_ptr(&13usize, TD_CanDowncast);
419 ///
420 /// assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&13usize));
421 /// assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
422 /// }
423 /// {
424 /// let mmut = &mut 21usize;
425 /// // `#[sabi_trait]` trait objects constructed from `&mut`
426 /// // use `RMut<'_, ()>` instead of `&'_ mut ()`
427 /// // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
428 /// let to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_CanDowncast);
429 ///
430 /// assert_eq!(to.obj.downcast_as::<usize>().ok(), Some(&21usize));
431 /// assert_eq!(to.obj.downcast_as::<u8>().ok(), None);
432 /// }
433 ///
434 /// ```
435 pub fn downcast_as<T>(&self) -> Result<&T, UneraseError<&Self>>
436 where
437 T: 'static,
438 P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
439 {
440 check_unerased!(self, self.sabi_check_same_utypeid::<T>());
441 unsafe { Ok(&*(self.ptr.as_ptr() as *const T)) }
442 }
443
444 /// Attempts to unerase this trait object into a mutable reference of
445 /// the value was constructed with.
446 ///
447 /// # Errors
448 ///
449 /// This will return an error in any of these conditions:
450 ///
451 /// - It is called in a dynamic library/binary outside
452 /// the one from which this RObject was constructed.
453 ///
454 /// - The trait object wrapping this `RObject` was constructed with a
455 /// `TD_CanDowncast` argument.
456 ///
457 /// - `T` is not the concrete type this `RObject<_>` was constructed with.
458 ///
459 ///
460 /// # Example
461 ///
462 /// ```rust
463 /// use abi_stable::{
464 /// sabi_trait::doc_examples::Doer_TO, std_types::RBox,
465 /// type_level::downcasting::TD_CanDowncast, RMut, RRef,
466 /// };
467 ///
468 /// {
469 /// let mut to: Doer_TO<'_, RBox<()>> =
470 /// Doer_TO::from_value(34usize, TD_CanDowncast);
471 ///
472 /// // `to.obj` is an RObject
473 /// assert_eq!(to.obj.downcast_as_mut::<usize>().ok(), Some(&mut 34usize));
474 /// assert_eq!(to.obj.downcast_as_mut::<u8>().ok(), None);
475 /// }
476 /// {
477 /// let mmut = &mut 55usize;
478 /// // `#[sabi_trait]` trait objects constructed from `&mut`
479 /// // use `RMut<'_, ()>` instead of `&'_ mut ()`
480 /// // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
481 /// let mut to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_CanDowncast);
482 ///
483 /// assert_eq!(to.obj.downcast_as_mut::<usize>().ok(), Some(&mut 55usize));
484 /// assert_eq!(to.obj.downcast_as_mut::<u8>().ok(), None);
485 /// }
486 ///
487 /// ```
488 pub fn downcast_as_mut<T>(&mut self) -> Result<&mut T, UneraseError<&mut Self>>
489 where
490 T: 'static,
491 P: AsMutPtr<PtrTarget = ()> + CanTransmuteElement<T>,
492 {
493 check_unerased!(self, self.sabi_check_same_utypeid::<T>());
494 unsafe { Ok(&mut *(self.ptr.as_mut_ptr() as *mut T)) }
495 }
496
497 /// Unwraps the `RObject<_>` into a pointer to T,
498 /// without checking whether `T` is the type that the RObject was constructed with.
499 ///
500 /// # Safety
501 ///
502 /// You must check that `T` is the type that RObject was constructed
503 /// with through other means.
504 ///
505 /// # Example
506 ///
507 /// ```rust
508 /// use abi_stable::{
509 /// sabi_trait::doc_examples::Doer_TO, std_types::RBox,
510 /// type_level::downcasting::TD_Opaque,
511 /// };
512 ///
513 /// let to = || Doer_TO::from_value(5usize, TD_Opaque);
514 ///
515 /// unsafe {
516 /// // `to.obj` is an RObject
517 /// assert_eq!(
518 /// to().obj.unchecked_downcast_into::<usize>(),
519 /// RBox::new(5usize)
520 /// );
521 /// }
522 /// ```
523 #[inline]
524 pub unsafe fn unchecked_downcast_into<T>(self) -> P::TransmutedPtr
525 where
526 P: AsPtr<PtrTarget = ()> + CanTransmuteElement<T>,
527 {
528 let this = ManuallyDrop::new(self);
529 unsafe { ptr::read(&*this.ptr).transmute_element::<T>() }
530 }
531
532 /// Unwraps the `RObject<_>` into a reference to T,
533 /// without checking whether `T` is the type that the RObject was constructed with.
534 ///
535 /// # Safety
536 ///
537 /// You must check that `T` is the type that RObject was constructed
538 /// with through other means.
539 ///
540 /// # Example
541 ///
542 /// ```rust
543 /// use abi_stable::{
544 /// sabi_trait::doc_examples::Doer_TO, std_types::RArc,
545 /// type_level::downcasting::TD_Opaque, RMut, RRef,
546 /// };
547 ///
548 /// {
549 /// let to: Doer_TO<'_, RArc<()>> = Doer_TO::from_ptr(RArc::new(8usize), TD_Opaque);
550 ///
551 /// unsafe {
552 /// // `to.obj` is an RObject
553 /// assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &8usize);
554 /// }
555 /// }
556 /// {
557 /// // `#[sabi_trait]` trait objects constructed from `&`
558 /// // use `RRef<'_, ()>` instead of `&'_ ()`
559 /// // since `&T` can't soundly be transmuted back and forth into `&()`
560 /// let to: Doer_TO<'_, RRef<'_, ()>> = Doer_TO::from_ptr(&13usize, TD_Opaque);
561 ///
562 /// unsafe {
563 /// assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &13usize);
564 /// }
565 /// }
566 /// {
567 /// let mmut = &mut 21usize;
568 /// // `#[sabi_trait]` trait objects constructed from `&mut`
569 /// // use `RMut<'_, ()>` instead of `&'_ mut ()`
570 /// // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
571 /// let to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_Opaque);
572 ///
573 /// unsafe {
574 /// assert_eq!(to.obj.unchecked_downcast_as::<usize>(), &21usize);
575 /// }
576 /// }
577 ///
578 /// ```
579 #[inline]
580 pub unsafe fn unchecked_downcast_as<T>(&self) -> &T
581 where
582 P: AsPtr<PtrTarget = ()>,
583 {
584 unsafe { &*(self.ptr.as_ptr() as *const T) }
585 }
586
587 /// Unwraps the `RObject<_>` into a mutable reference to T,
588 /// without checking whether `T` is the type that the RObject was constructed with.
589 ///
590 /// # Safety
591 ///
592 /// You must check that `T` is the type that RObject was constructed
593 /// with through other means.
594 ///
595 /// # Example
596 ///
597 /// ```rust
598 /// use abi_stable::{
599 /// sabi_trait::doc_examples::Doer_TO, std_types::RBox,
600 /// type_level::downcasting::TD_Opaque, RMut, RRef,
601 /// };
602 ///
603 /// {
604 /// let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(34usize, TD_Opaque);
605 ///
606 /// unsafe {
607 /// // `to.obj` is an RObject
608 /// assert_eq!(to.obj.unchecked_downcast_as_mut::<usize>(), &mut 34usize);
609 /// }
610 /// }
611 /// {
612 /// let mmut = &mut 55usize;
613 /// // `#[sabi_trait]` trait objects constructed from `&mut`
614 /// // use `RMut<'_, ()>` instead of `&'_ mut ()`
615 /// // since `&mut T` can't soundly be transmuted back and forth into `&mut ()`
616 /// let mut to: Doer_TO<'_, RMut<'_, ()>> = Doer_TO::from_ptr(mmut, TD_Opaque);
617 ///
618 /// unsafe {
619 /// assert_eq!(to.obj.unchecked_downcast_as_mut::<usize>(), &mut 55usize);
620 /// }
621 /// }
622 ///
623 /// ```
624 #[inline]
625 pub unsafe fn unchecked_downcast_as_mut<T>(&mut self) -> &mut T
626 where
627 P: AsMutPtr<PtrTarget = ()>,
628 {
629 unsafe { &mut *(self.ptr.as_mut_ptr() as *mut T) }
630 }
631}
632
633mod private_struct {
634 pub struct PrivStruct;
635}
636use self::private_struct::PrivStruct;
637
638/// This is used to make sure that reborrowing does not change
639/// the Send-ness or Sync-ness of the pointer.
640pub trait ReborrowBounds<SendNess, SyncNess> {}
641
642// If it's reborrowing, it must have either both Sync+Send or neither.
643impl ReborrowBounds<Unimplemented<trait_marker::Send>, Unimplemented<trait_marker::Sync>>
644 for PrivStruct
645{
646}
647
648impl ReborrowBounds<Implemented<trait_marker::Send>, Implemented<trait_marker::Sync>>
649 for PrivStruct
650{
651}
652
653impl<'lt, P, I, V> RObject<'lt, P, I, V>
654where
655 P: GetPointerKind,
656 I: InterfaceType,
657{
658 /// Creates a shared reborrow of this RObject.
659 ///
660 /// This is only callable if `RObject` is either `Send + Sync` or `!Send + !Sync`.
661 ///
662 /// # Example
663 ///
664 /// ```rust
665 /// use abi_stable::{
666 /// sabi_trait::doc_examples::Doer_TO, std_types::RBox,
667 /// type_level::downcasting::TD_Opaque, RMut, RRef,
668 /// };
669 ///
670 /// let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(13usize, TD_Opaque);
671 ///
672 /// // `to.obj` is an RObject
673 /// assert_eq!(debug_string(to.obj.reborrow()), "13");
674 /// assert_eq!(debug_string(to.obj.reborrow()), "13");
675 ///
676 /// // `#[sabi_trait]` trait objects have an equivalent `sabi_reborrow` method.
677 /// assert_eq!(debug_string(to.sabi_reborrow()), "13");
678 /// assert_eq!(debug_string(to.sabi_reborrow()), "13");
679 ///
680 /// fn debug_string<T>(to: T) -> String
681 /// where
682 /// T: std::fmt::Debug,
683 /// {
684 /// format!("{:?}", to)
685 /// }
686 ///
687 /// ```
688 pub fn reborrow<'re>(&'re self) -> RObject<'lt, RRef<'re, ()>, I, V>
689 where
690 P: AsPtr<PtrTarget = ()>,
691 PrivStruct: ReborrowBounds<I::Send, I::Sync>,
692 {
693 // Reborrowing will break if I add extra functions that operate on `P`.
694 RObject {
695 vtable: self.vtable,
696 ptr: ManuallyDrop::new(self.ptr.as_rref()),
697 _marker: PhantomData,
698 }
699 }
700
701 /// Creates a mutable reborrow of this RObject.
702 ///
703 /// The reborrowed RObject cannot use these methods:
704 ///
705 /// - RObject::clone
706 ///
707 /// This is only callable if `RObject` is either `Send + Sync` or `!Send + !Sync`.
708 ///
709 /// # Example
710 ///
711 /// ```rust
712 /// use abi_stable::{
713 /// sabi_trait::doc_examples::{Doer, Doer_TO},
714 /// std_types::RBox,
715 /// type_level::downcasting::TD_Opaque,
716 /// RMut, RRef,
717 /// };
718 ///
719 /// let mut to: Doer_TO<'_, RBox<()>> = Doer_TO::from_value(2usize, TD_Opaque);
720 ///
721 /// // `#[sabi_trait]` trait objects have an equivalent `sabi_reborrow_mut` method,
722 /// // which delegate to this method.
723 /// assert_eq!(increment(to.sabi_reborrow_mut()).value(), 3);
724 /// assert_eq!(increment(to.sabi_reborrow_mut()).value(), 4);
725 ///
726 /// fn increment<T>(mut to: T) -> T
727 /// where
728 /// T: Doer,
729 /// {
730 /// to.add_into(1);
731 /// to
732 /// }
733 ///
734 /// ```
735 pub fn reborrow_mut<'re>(&'re mut self) -> RObject<'lt, RMut<'re, ()>, I, V>
736 where
737 P: AsMutPtr<PtrTarget = ()>,
738 PrivStruct: ReborrowBounds<I::Send, I::Sync>,
739 {
740 // Reborrowing will break if I add extra functions that operate on `P`.
741 RObject {
742 vtable: self.vtable,
743 ptr: ManuallyDrop::new(self.ptr.as_rmut()),
744 _marker: PhantomData,
745 }
746 }
747}
748
749impl<'lt, P, I, V> RObject<'lt, P, I, V>
750where
751 P: GetPointerKind,
752{
753 /// Gets the vtable.
754 #[inline]
755 pub const fn sabi_et_vtable(&self) -> PrefixRef<V> {
756 self.vtable
757 }
758
759 /// The vtable common to all `#[sabi_trait]` generated trait objects.
760 #[inline]
761 pub fn sabi_robject_vtable(&self) -> RObjectVtable_Ref<(), P, I> {
762 unsafe { BaseVtable_Ref(self.vtable.cast::<BaseVtable_Prefix<(), P, I>>())._sabi_vtable() }
763 }
764
765 #[inline]
766 fn sabi_into_erased_ptr(self) -> ManuallyDrop<P> {
767 let __this = ManuallyDrop::new(self);
768 unsafe { ptr::read(&__this.ptr) }
769 }
770
771 /// Gets an `RRef` pointing to the erased object.
772 pub fn sabi_erased_ref(&self) -> RRef<'_, ErasedObject<()>>
773 where
774 P: AsPtr<PtrTarget = ()>,
775 {
776 unsafe { RRef::from_raw(self.ptr.as_ptr() as *const _) }
777 }
778
779 /// Gets an `RMut` pointing to the erased object.
780 pub fn sabi_erased_mut(&mut self) -> RMut<'_, ErasedObject<()>>
781 where
782 P: AsMutPtr<PtrTarget = ()>,
783 {
784 unsafe { RMut::from_raw(self.ptr.as_mut_ptr() as *mut _) }
785 }
786
787 /// Gets an `RRef` pointing to the erased object.
788 pub fn sabi_as_rref(&self) -> RRef<'_, ()>
789 where
790 P: AsPtr<PtrTarget = ()>,
791 {
792 self.ptr.as_rref()
793 }
794
795 /// Gets an `RMut` pointing to the erased object.
796 pub fn sabi_as_rmut(&mut self) -> RMut<'_, ()>
797 where
798 P: AsMutPtr<PtrTarget = ()>,
799 {
800 self.ptr.as_rmut()
801 }
802
803 /// Calls the `f` callback with an `MovePtr` pointing to the erased object.
804 #[inline]
805 pub fn sabi_with_value<F, R>(self, f: F) -> R
806 where
807 P: OwnedPointer<PtrTarget = ()>,
808 F: FnOnce(MovePtr<'_, ()>) -> R,
809 {
810 OwnedPointer::with_move_ptr(self.sabi_into_erased_ptr(), f)
811 }
812}
813
814impl<'lt, I, V> RObject<'lt, crate::std_types::RArc<()>, I, V> {
815 /// Does a shallow clone of the object, just incrementing the reference counter
816 pub fn shallow_clone(&self) -> Self {
817 Self {
818 vtable: self.vtable,
819 ptr: self.ptr.clone(),
820 _marker: PhantomData,
821 }
822 }
823}
824
825impl<P, I, V> Drop for RObject<'_, P, I, V>
826where
827 P: GetPointerKind,
828{
829 fn drop(&mut self) {
830 // This condition is necessary because if the RObject was reborrowed,
831 // the destructor function would take a different pointer type.
832 if <P as GetPointerKind>::KIND == PointerKind::SmartPointer {
833 let destructor = self.sabi_robject_vtable()._sabi_drop();
834 unsafe {
835 destructor(RMut::<P>::new(&mut self.ptr));
836 }
837 }
838 }
839}
840
841//////////////////////////////////////////////////////////////////
842
843/// Error for `RObject<_>` being downcasted into the wrong type
844/// with one of the `*downcast*` methods.
845#[derive(Copy, Clone)]
846pub struct UneraseError<T> {
847 robject: T,
848 expected_typeid: MaybeCmp<UTypeId>,
849 actual_typeid: UTypeId,
850}
851
852#[allow(clippy::missing_const_for_fn)]
853impl<T> UneraseError<T> {
854 fn map<F, U>(self, f: F) -> UneraseError<U>
855 where
856 F: FnOnce(T) -> U,
857 {
858 UneraseError {
859 robject: f(self.robject),
860 expected_typeid: self.expected_typeid,
861 actual_typeid: self.actual_typeid,
862 }
863 }
864
865 /// Extracts the RObject, to handle the failure to unerase it.
866 #[must_use]
867 pub fn into_inner(self) -> T {
868 self.robject
869 }
870}
871
872impl<D> fmt::Debug for UneraseError<D> {
873 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
874 f.debug_struct("UneraseError")
875 .field("dyn_trait", &"<not shown>")
876 .field("expected_typeid", &self.expected_typeid)
877 .field("actual_typeid", &self.actual_typeid)
878 .finish()
879 }
880}
881
882impl<D> fmt::Display for UneraseError<D> {
883 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
884 fmt::Debug::fmt(self, f)
885 }
886}
887
888impl<D> ::std::error::Error for UneraseError<D> {}
889
890//////////////////////////////////////////////////////////////////