abi_stable/sabi_types/
rref.rs

1use std::{
2    fmt::{self, Display},
3    marker::PhantomData,
4    ptr::NonNull,
5};
6
7use crate::{
8    pointer_trait::{AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference},
9    utils::ref_as_nonnull,
10};
11
12/// Equivalent to `&'a T`,
13/// which allows a few more operations without causing Undefined Behavior.
14///
15/// # Purpose
16///
17/// This type is used as the `&self` parameter in abi_stable trait objects
18/// because it can be soundly transmuted
19/// to point to other smaller but compatible types, then back to the original type.
20///
21/// This crate is tested with [miri] to detect bugs in unsafe code,
22/// which implements the  [Stacked Borrows model].
23/// Because that model forbids `&T` to `&()`  to `&T` transmutes (when `T` isn't zero-sized),
24/// it required defining `RRef` to allow a reference-like type that can be transmuted.
25///
26/// # Example
27///
28/// This example demonstrates how a simple `&dyn Any`-like type can be implemented.
29///
30/// ```rust
31/// use abi_stable::{marker_type::ErasedObject, std_types::UTypeId, RRef};
32///
33/// fn main() {
34///     let value = WithTypeId::new(5u32);
35///     let erased = value.erase();
36///
37///     assert_eq!(WithTypeId::downcast::<i32>(erased), None);
38///     assert_eq!(WithTypeId::downcast::<bool>(erased), None);
39///     assert_eq!(WithTypeId::downcast::<u32>(erased), Some(&value));
40/// }
41///
42/// // `#[repr(C))]` with a trailing `T` field is required for soundly transmuting from
43/// // `RRef<'a, WithTypeId<T>>` to `RRef<'a, WithTypeId<ErasedObject>>`.
44/// #[repr(C)]
45/// #[derive(Debug, PartialEq)]
46/// struct WithTypeId<T> {
47///     type_id: UTypeId,
48///     value: T,
49/// }
50///
51/// impl<T> WithTypeId<T> {
52///     pub fn new(value: T) -> Self
53///     where
54///         T: 'static,
55///     {
56///         Self {
57///             type_id: UTypeId::new::<T>(),
58///             value,
59///         }
60///     }
61///
62///     pub fn erase(&self) -> RRef<'_, WithTypeId<ErasedObject>> {
63///         unsafe { RRef::new(self).transmute::<WithTypeId<ErasedObject>>() }
64///     }
65/// }
66///
67/// impl WithTypeId<ErasedObject> {
68///     pub fn downcast<T>(this: RRef<'_, Self>) -> Option<&WithTypeId<T>>
69///     where
70///         T: 'static,
71///     {
72///         if this.get().type_id == UTypeId::new::<T>() {
73///             // safety: we checked that type parameter was `T`
74///             unsafe { Some(this.transmute_into_ref::<WithTypeId<T>>()) }
75///         } else {
76///             None
77///         }
78///     }
79/// }
80///
81///
82/// ```
83///
84/// <span id="type-prefix-exp"></span>
85/// # Type Prefix
86///
87/// A type parameter `U` is considered a prefix of `T` in all of these cases:
88///
89/// - `U` is a zero-sized type with an alignment equal or lower than `T`
90///
91/// - `U` is a `#[repr(transparent)]` wrapper over `T`
92///
93/// - `U` and `T` are both `#[repr(C)]` structs,
94/// in which `T` starts with the fields of `U` in the same order,
95/// and `U` has an alignment equal to or lower than `T`.
96///
97/// Please note that it can be unsound to transmute a non-local
98/// type if it has private fields,
99/// since it may assume it was constructed in a particular way.
100///
101/// [Stacked Borrows model]:
102/// https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md
103///
104/// [miri]: https://github.com/rust-lang/miri
105///
106#[repr(transparent)]
107#[derive(StableAbi)]
108#[sabi(bound(T:'a))]
109pub struct RRef<'a, T> {
110    ref_: NonNull<T>,
111    _marker: PhantomData<&'a T>,
112}
113
114impl<'a, T> Display for RRef<'a, T>
115where
116    T: Display,
117{
118    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119        Display::fmt(self.get(), f)
120    }
121}
122
123impl<'a, T> Clone for RRef<'a, T> {
124    fn clone(&self) -> Self {
125        *self
126    }
127}
128
129impl<'a, T> Copy for RRef<'a, T> {}
130
131unsafe impl<'a, T> Sync for RRef<'a, T> where &'a T: Sync {}
132
133unsafe impl<'a, T> Send for RRef<'a, T> where &'a T: Send {}
134
135shared_impls! {
136    mod=static_ref_impls
137    new_type=RRef['a][T],
138    original_type=AAAA,
139    deref_approach=(method = get),
140}
141
142impl<'a, T> RRef<'a, T> {
143    /// Constructs this RRef from a reference.
144    ///
145    /// # Example
146    ///
147    /// ```
148    /// use abi_stable::sabi_types::RRef;
149    ///
150    /// struct GetPtr<'a, T>(&'a T);
151    ///
152    /// impl<'a, T: 'a> GetPtr<'a, T> {
153    ///     const REF: &'a Option<T> = &None;
154    ///
155    ///     const STATIC: RRef<'a, Option<T>> = RRef::new(Self::REF);
156    /// }
157    ///
158    /// ```
159    #[inline(always)]
160    pub const fn new(ref_: &'a T) -> Self {
161        Self {
162            ref_: ref_as_nonnull(ref_),
163            _marker: PhantomData,
164        }
165    }
166
167    /// Constructs this RRef from a raw pointer.
168    ///
169    /// # Safety
170    ///
171    /// You must ensure that the raw pointer is valid for the `'a` lifetime,
172    /// and points to a fully initialized and aligned `T`.
173    ///
174    /// # Example
175    ///
176    /// ```
177    /// use abi_stable::sabi_types::RRef;
178    ///
179    /// struct GetPtr<'a, T>(&'a T);
180    ///
181    /// impl<'a, T: 'a> GetPtr<'a, T> {
182    ///     const PTR: *const Option<T> = &None;
183    ///
184    ///     const STATIC: RRef<'a, Option<T>> = unsafe { RRef::from_raw(Self::PTR) };
185    /// }
186    ///
187    /// ```
188    #[inline(always)]
189    pub const unsafe fn from_raw(ref_: *const T) -> Self
190    where
191        T: 'a,
192    {
193        Self {
194            ref_: unsafe { NonNull::new_unchecked(ref_ as *mut T) },
195            _marker: PhantomData,
196        }
197    }
198
199    /// Casts this to an equivalent reference.
200    ///
201    /// # Example
202    ///
203    /// ```rust
204    /// use abi_stable::RRef;
205    ///
206    /// let rref = RRef::new(&89);
207    ///
208    /// assert_eq!(rref.get(), &89);
209    ///
210    /// ```
211    #[inline(always)]
212    pub const fn get(self) -> &'a T {
213        unsafe { crate::utils::deref!(self.ref_.as_ptr()) }
214    }
215
216    /// Copies the value that this points to.
217    ///
218    /// # Example
219    ///
220    /// ```rust
221    /// use abi_stable::RRef;
222    ///
223    /// let rref = RRef::new(&55);
224    ///
225    /// assert_eq!(rref.get_copy(), 55);
226    ///
227    /// ```
228    #[inline(always)]
229    pub const fn get_copy(self) -> T
230    where
231        T: Copy,
232    {
233        unsafe { *(self.ref_.as_ptr() as *const T) }
234    }
235
236    /// Casts this to an equivalent raw pointer.
237    ///
238    /// # Example
239    ///
240    /// ```rust
241    /// use abi_stable::RRef;
242    ///
243    /// let rref = RRef::new(&89);
244    ///
245    /// unsafe {
246    ///     assert_eq!(*rref.as_ptr(), 89);
247    /// }
248    /// ```
249    #[inline(always)]
250    pub const fn as_ptr(self) -> *const T {
251        self.ref_.as_ptr() as *const T
252    }
253
254    /// Transmutes this `RRef<'a,T>` to a `RRef<'a,U>`.
255    ///
256    /// # Safety
257    ///
258    /// Either of these must be the case:
259    ///
260    /// - [`U` is a prefix of `T`](#type-prefix-exp)
261    ///
262    /// - `RRef<'a, U>` was the original type of this `RRef<'a, T>`.
263    ///
264    /// # Example
265    ///
266    /// ```
267    /// use abi_stable::RRef;
268    ///
269    /// use std::num::Wrapping;
270    ///
271    /// let rref = RRef::new(&13u32);
272    ///
273    /// // safety: Wrapping is a `#[repr(transparent)]` wrapper with one `pub` field.
274    /// let trans = unsafe { rref.transmute::<Wrapping<u32>>() };
275    ///
276    /// assert_eq!(trans, RRef::new(&Wrapping(13u32)));
277    ///
278    ///
279    /// ```
280    #[inline(always)]
281    pub const unsafe fn transmute<U>(self) -> RRef<'a, U>
282    where
283        U: 'a,
284    {
285        unsafe { RRef::from_raw(self.ref_.as_ptr() as *const U) }
286    }
287
288    /// Transmutes this to a raw pointer pointing to a different type.
289    #[inline(always)]
290    pub const fn transmute_into_raw<U>(self) -> *const U {
291        self.ref_.as_ptr() as *const T as *const U
292    }
293
294    /// Transmutes this to a reference pointing to a different type.
295    ///
296    /// # Safety
297    ///
298    /// Either of these must be the case:
299    ///
300    /// - [`U` is a prefix of `T`](#type-prefix-exp)
301    ///
302    /// - `RRef<'a, U>` was the original type of this `RRef<'a, T>`.
303    ///
304    /// # Example
305    ///
306    /// ```rust
307    /// use abi_stable::{std_types::Tuple2, RRef};
308    ///
309    /// unsafe {
310    ///     let reff = RRef::new(&Tuple2(3u32, 5u64));
311    ///     assert_eq!(reff.transmute_into_ref::<u32>(), &3u32);
312    /// }
313    ///
314    /// ```
315    #[inline(always)]
316    pub const unsafe fn transmute_into_ref<U>(self) -> &'a U
317    where
318        U: 'a,
319    {
320        unsafe { crate::utils::deref!(self.ref_.as_ptr() as *const T as *const U) }
321    }
322}
323
324unsafe impl<'a, T> GetPointerKind for RRef<'a, T> {
325    type Kind = PK_Reference;
326
327    type PtrTarget = T;
328}
329
330unsafe impl<'a, T, U> CanTransmuteElement<U> for RRef<'a, T>
331where
332    U: 'a,
333{
334    type TransmutedPtr = RRef<'a, U>;
335
336    #[inline(always)]
337    unsafe fn transmute_element_(self) -> Self::TransmutedPtr {
338        unsafe { self.transmute() }
339    }
340}
341
342unsafe impl<T> AsPtr for RRef<'_, T> {
343    #[inline(always)]
344    fn as_ptr(&self) -> *const T {
345        self.ref_.as_ptr() as *const T
346    }
347
348    #[inline(always)]
349    fn as_rref(&self) -> RRef<'_, T> {
350        *self
351    }
352}
353
354#[cfg(test)]
355mod tests {
356    use super::*;
357
358    #[test]
359    fn construction_test() {
360        unsafe {
361            let three: *const i32 = &3;
362            assert_eq!(RRef::from_raw(three).get_copy(), 3);
363        }
364
365        assert_eq!(RRef::new(&5).get_copy(), 5);
366    }
367
368    #[test]
369    fn access() {
370        let reference = RRef::new(&8);
371
372        assert_eq!(*reference.get(), 8);
373        assert_eq!(reference.get_copy(), 8);
374        unsafe {
375            assert_eq!(*reference.as_ptr(), 8);
376        }
377    }
378
379    #[test]
380    fn transmutes() {
381        let reference = RRef::new(&(!0u32));
382
383        unsafe {
384            assert_eq!(reference.transmute::<i32>().get_copy(), -1);
385            assert_eq!(*reference.transmute_into_raw::<i32>(), -1);
386            assert_eq!(reference.transmute_into_ref::<i32>(), &-1);
387        }
388    }
389
390    #[test]
391    fn as_ptr_impl() {
392        let reference = RRef::new(&89u32);
393
394        unsafe {
395            assert_eq!(*AsPtr::as_ptr(&reference), 89);
396            assert_eq!(AsPtr::as_rref(&reference), reference);
397        }
398    }
399}