abi_stable/sabi_types/
static_ref.rs

1use crate::pointer_trait::{AsPtr, CanTransmuteElement, GetPointerKind, PK_Reference};
2
3use std::{
4    fmt::{self, Display},
5    ops::Deref,
6    ptr::NonNull,
7};
8
9/// A wrapper type for vtable static references,
10/// and other constants that have `non-'static` generic parameters
11/// but are safe to reference for the lifetime of `T`.
12///
13/// # Purpose
14///
15/// This type is necessary because Rust doesn't understand that vtables live for `'static`,
16/// even though they have `non-'static` type parameters.
17///
18/// # Example
19///
20/// This defines a non-extensible vtable,using a StaticRef as the pointer to the vtable.
21///
22/// ```
23/// use abi_stable::{
24///     marker_type::ErasedObject,
25///     prefix_type::{PrefixTypeTrait, WithMetadata},
26///     sabi_extern_fn,
27///     sabi_types::StaticRef,
28///     staticref, StableAbi,
29/// };
30///
31/// use std::{marker::PhantomData, ops::Deref};
32///
33/// fn main() {
34///     let boxed = BoxLike::new("foo".to_string());
35///     assert_eq!(boxed.as_str(), "foo");
36/// }
37///
38/// /// An ffi-safe `Box<T>`
39/// #[repr(C)]
40/// #[derive(StableAbi)]
41/// pub struct BoxLike<T> {
42///     data: *mut T,
43///
44///     vtable: StaticRef<VTable<T>>,
45///
46///     _marker: PhantomData<T>,
47/// }
48///
49/// impl<T> BoxLike<T> {
50///     pub fn new(value: T) -> Self {
51///         Self {
52///             data: Box::into_raw(Box::new(value)),
53///             vtable: VTable::<T>::VTABLE,
54///             _marker: PhantomData,
55///         }
56///     }
57/// }
58///
59/// impl<T> Drop for BoxLike<T> {
60///     fn drop(&mut self) {
61///         unsafe {
62///             (self.vtable.drop_)(self.data);
63///         }
64///     }
65/// }
66///
67/// impl<T> Deref for BoxLike<T> {
68///     type Target = T;
69///
70///     fn deref(&self) -> &T {
71///         unsafe { &*self.data }
72///     }
73/// }
74///
75/// #[repr(C)]
76/// #[derive(StableAbi)]
77/// pub struct VTable<T> {
78///     drop_: unsafe extern "C" fn(*mut T),
79/// }
80///
81/// impl<T> VTable<T> {
82///     // The `staticref` macro declares a `StaticRef<VTable<T>>` constant.
83///     staticref!(const VTABLE: Self = Self{
84///         drop_: drop_box::<T>,
85///     });
86/// }
87///
88/// #[sabi_extern_fn]
89/// unsafe fn drop_box<T>(object: *mut T) {
90///     drop(Box::from_raw(object));
91/// }
92///
93/// ```
94#[repr(transparent)]
95#[derive(StableAbi)]
96pub struct StaticRef<T> {
97    ref_: NonNull<T>,
98}
99
100impl<T> Display for StaticRef<T>
101where
102    T: Display,
103{
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        Display::fmt(&**self, f)
106    }
107}
108
109impl<T> Clone for StaticRef<T> {
110    fn clone(&self) -> Self {
111        *self
112    }
113}
114
115impl<T> Copy for StaticRef<T> {}
116
117unsafe impl<'a, T: 'a> Sync for StaticRef<T> where &'a T: Sync {}
118
119unsafe impl<'a, T: 'a> Send for StaticRef<T> where &'a T: Send {}
120
121shared_impls! {
122    mod=static_ref_impls
123    new_type=StaticRef[][T],
124    original_type=AAAA,
125}
126
127impl<T> StaticRef<T> {
128    /// Constructs this StaticRef from a raw pointer.
129    ///
130    /// # Safety
131    ///
132    /// You must ensure that the raw pointer is valid for the entire program's lifetime.
133    ///
134    /// # Example
135    ///
136    /// ```
137    /// use abi_stable::sabi_types::StaticRef;
138    ///
139    /// struct GetPtr<T>(T);
140    ///
141    /// impl<T> GetPtr<T> {
142    ///     const PTR: *const Option<T> = &None;
143    ///
144    ///     const STATIC: StaticRef<Option<T>> = unsafe { StaticRef::from_raw(Self::PTR) };
145    /// }
146    /// {}
147    /// ```
148    pub const unsafe fn from_raw(ref_: *const T) -> Self {
149        Self {
150            ref_: unsafe { NonNull::new_unchecked(ref_ as *mut T) },
151        }
152    }
153
154    /// Constructs this StaticRef from a static reference
155    ///
156    /// This implicitly requires that `T:'static`.
157    ///
158    /// # Example
159    ///
160    /// ```
161    /// use abi_stable::sabi_types::StaticRef;
162    ///
163    /// struct GetPtr<T>(T);
164    ///
165    /// impl<T> GetPtr<T>
166    /// where
167    ///     T: 'static,
168    /// {
169    ///     const REF: &'static Option<T> = &None;
170    ///
171    ///     const STATIC: StaticRef<Option<T>> = StaticRef::new(Self::REF);
172    /// }
173    ///
174    /// ```
175    pub const fn new(ref_: &'static T) -> Self {
176        Self {
177            ref_: unsafe { NonNull::new_unchecked(ref_ as *const T as *mut T) },
178        }
179    }
180
181    /// Creates a StaticRef by heap allocating and leaking `val`.
182    pub fn leak_value(val: T) -> Self {
183        // Safety: This is safe, because the value is a leaked heap allocation.
184        unsafe { Self::from_raw(crate::utils::leak_value(val)) }
185    }
186
187    /// Gets access to the reference.
188    ///
189    /// This returns `&'a T` instead of `&'static T` to support vtables of `non-'static` types.
190    ///
191    /// # Example
192    ///
193    /// ```
194    /// use abi_stable::sabi_types::StaticRef;
195    ///
196    /// struct GetPtr<T>(T);
197    ///
198    /// impl<T> GetPtr<T> {
199    ///     const PTR: *const Option<T> = &None;
200    ///
201    ///     const STATIC: StaticRef<Option<T>> = unsafe { StaticRef::from_raw(Self::PTR) };
202    /// }
203    ///
204    /// let reference: &'static Option<String> = GetPtr::<String>::STATIC.get();
205    ///
206    /// ```
207    pub const fn get<'a>(self) -> &'a T {
208        unsafe { crate::utils::deref!(self.ref_.as_ptr() as *const T) }
209    }
210
211    /// Gets access to the referenced value,as a raw pointer.
212    ///
213    /// # Example
214    ///
215    /// ```
216    /// use abi_stable::sabi_types::StaticRef;
217    /// use std::convert::Infallible;
218    ///
219    /// struct GetPtr<T>(T);
220    ///
221    /// impl<T> GetPtr<T> {
222    ///     const PTR: *const Option<T> = &None;
223    ///
224    ///     const STATIC: StaticRef<Option<T>> = unsafe { StaticRef::from_raw(Self::PTR) };
225    /// }
226    ///
227    /// let reference: *const Option<Infallible> = GetPtr::<Infallible>::STATIC.as_ptr();
228    ///
229    /// ```
230    pub const fn as_ptr(self) -> *const T {
231        self.ref_.as_ptr() as *const T
232    }
233
234    /// Transmutes this `StaticRef<T>` to a `StaticRef<U>`.
235    ///
236    /// # Safety
237    ///
238    /// StaticRef has the same rules that references have regarding
239    /// transmuting from one type to another:
240    ///
241    /// # Example
242    ///
243    /// ```
244    /// use abi_stable::sabi_types::StaticRef;
245    ///
246    /// struct GetPtr<T>(T);
247    ///
248    /// impl<T> GetPtr<T> {
249    ///     const PTR: *const Option<T> = &None;
250    ///
251    ///     const STATIC: StaticRef<Option<T>> = unsafe { StaticRef::from_raw(Self::PTR) };
252    /// }
253    ///
254    /// let reference: StaticRef<Option<[(); 0xFFF_FFFF]>> =
255    ///     unsafe { GetPtr::<()>::STATIC.transmute::<Option<[(); 0xFFF_FFFF]>>() };
256    ///
257    /// ```
258    pub const unsafe fn transmute<U>(self) -> StaticRef<U> {
259        unsafe { StaticRef::from_raw(self.ref_.as_ptr() as *const T as *const U) }
260    }
261}
262
263impl<T> Deref for StaticRef<T> {
264    type Target = T;
265
266    fn deref(&self) -> &T {
267        self.get()
268    }
269}
270
271unsafe impl<T> AsPtr for StaticRef<T> {
272    fn as_ptr(&self) -> *const T {
273        self.ref_.as_ptr() as *const T
274    }
275}
276
277unsafe impl<T> GetPointerKind for StaticRef<T> {
278    type Kind = PK_Reference;
279
280    type PtrTarget = T;
281}
282
283unsafe impl<T, U> CanTransmuteElement<U> for StaticRef<T> {
284    type TransmutedPtr = StaticRef<U>;
285
286    #[inline(always)]
287    unsafe fn transmute_element_(self) -> StaticRef<U> {
288        unsafe { self.transmute() }
289    }
290}
291
292#[cfg(test)]
293mod tests {
294    use super::*;
295
296    #[test]
297    fn construction_test() {
298        unsafe {
299            let three: *const i32 = &3;
300            assert_eq!(*StaticRef::from_raw(three), 3);
301        }
302
303        assert_eq!(*StaticRef::new(&5), 5);
304
305        assert_eq!(*StaticRef::leak_value(8), 8);
306    }
307
308    #[test]
309    fn access() {
310        let reference = StaticRef::new(&8);
311        const SREF: StaticRef<u8> = StaticRef::new(&8);
312        const REF: &u8 = SREF.get();
313
314        assert_eq!(*reference.get(), 8);
315        assert_eq!(*REF, 8);
316        unsafe {
317            assert_eq!(*reference.as_ptr(), 8);
318        }
319    }
320
321    #[test]
322    fn transmutes() {
323        let reference = StaticRef::new(&(!0u32));
324
325        unsafe {
326            assert_eq!(*reference.transmute::<i32>(), -1);
327        }
328    }
329}