ptr_meta/
lib.rs

1//! A radioactive stabilization of the [`ptr_meta` RFC][rfc].
2//!
3//! [rfc]: https://rust-lang.github.io/rfcs/2580-ptr-meta.html
4//!
5//! ## Usage
6//!
7//! ### Sized types
8//!
9//! Sized types already have `Pointee` implemented for them, so most of the time you won't have to worry
10//! about them. However, trying to derive `Pointee` for a struct that may or may not have a DST as its
11//! last field will cause an implementation conflict with the automatic sized implementation.
12//!
13//! ### `slice`s and `str`s
14//!
15//! These core types have implementations built in.
16//!
17//! ### Structs with a DST as its last field
18//!
19//! You can derive `Pointee` for last-field DSTs:
20//!
21//! ```
22//! use ptr_meta::Pointee;
23//!
24//! #[derive(Pointee)]
25//! struct Block<H, T> {
26//!     header: H,
27//!     elements: [T],
28//! }
29//! ```
30//!
31//! ### Trait objects
32//!
33//! You can generate a `Pointee` for trait objects:
34//!
35//! ```
36//! use ptr_meta::pointee;
37//!
38//! // Generates Pointee for dyn Stringy
39//! #[pointee]
40//! trait Stringy {
41//!     fn as_string(&self) -> String;
42//! }
43//! ```
44
45#![cfg_attr(not(feature = "std"), no_std)]
46
47mod impls;
48
49use core::{
50    alloc::Layout,
51    cmp,
52    fmt,
53    hash,
54    marker::PhantomData,
55    ptr,
56};
57
58pub use ptr_meta_derive::{pointee, Pointee};
59
60/// Provides the pointer metadata type of any pointed-to type.
61///
62/// # Pointer metadata
63///
64/// Raw pointer types and reference types in Rust can be thought of as made of two parts:
65/// a data pointer that contains the memory address of the value, and some metadata.
66///
67/// For statically-sized types (that implement the `Sized` traits)
68/// as well as for `extern` types,
69/// pointers are said to be “thin”: metadata is zero-sized and its type is `()`.
70///
71/// Pointers to [dynamically-sized types][dst] are said to be “wide” or “fat”,
72/// they have non-zero-sized metadata:
73///
74/// * For structs whose last field is a DST, metadata is the metadata for the last field
75/// * For the `str` type, metadata is the length in bytes as `usize`
76/// * For slice types like `[T]`, metadata is the length in items as `usize`
77/// * For trait objects like `dyn SomeTrait`, metadata is [`DynMetadata<Self>`][DynMetadata]
78///   (e.g. `DynMetadata<dyn SomeTrait>`)
79///
80/// In the future, the Rust language may gain new kinds of types
81/// that have different pointer metadata.
82///
83/// [dst]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#dynamically-sized-types-dsts
84///
85///
86/// # The `Pointee` trait
87///
88/// The point of this trait is its `Metadata` associated type,
89/// which is `()` or `usize` or `DynMetadata<_>` as described above.
90/// It is automatically implemented for every type.
91/// It can be assumed to be implemented in a generic context, even without a corresponding bound.
92///
93///
94/// # Usage
95///
96/// Raw pointers can be decomposed into the data address and metadata components
97/// with their [`to_raw_parts`] method.
98///
99/// Alternatively, metadata alone can be extracted with the [`metadata`] function.
100/// A reference can be passed to [`metadata`] and implicitly coerced.
101///
102/// A (possibly-wide) pointer can be put back together from its address and metadata
103/// with [`from_raw_parts`] or [`from_raw_parts_mut`].
104///
105/// [`to_raw_parts`]: PtrExt::to_raw_parts
106pub trait Pointee {
107    /// The type for metadata in pointers and references to `Self`.
108    type Metadata: Copy + Send + Sync + Ord + hash::Hash + Unpin;
109}
110
111impl<T> Pointee for T {
112    type Metadata = ();
113}
114
115impl<T> Pointee for [T] {
116    type Metadata = usize;
117}
118
119impl Pointee for str {
120    type Metadata = usize;
121}
122
123#[cfg(feature = "std")]
124impl Pointee for ::std::ffi::CStr {
125    type Metadata = usize;
126}
127
128#[cfg(feature = "std")]
129impl Pointee for ::std::ffi::OsStr {
130    type Metadata = usize;
131}
132
133#[repr(C)]
134pub(crate) union PtrRepr<T: Pointee + ?Sized> {
135    pub(crate) const_ptr: *const T,
136    pub(crate) mut_ptr: *mut T,
137    pub(crate) components: PtrComponents<T>,
138}
139
140#[repr(C)]
141pub(crate) struct PtrComponents<T: Pointee + ?Sized> {
142    pub(crate) data_address: *const (),
143    pub(crate) metadata: <T as Pointee>::Metadata,
144}
145
146impl<T: Pointee + ?Sized> Clone for PtrComponents<T> {
147    fn clone(&self) -> Self {
148        Self {
149            data_address: self.data_address.clone(),
150            metadata: self.metadata.clone(),
151        }
152    }
153}
154
155impl<T: Pointee + ?Sized> Copy for PtrComponents<T> {}
156
157/// Extract the metadata component of a pointer.
158///
159/// Values of type `*mut T`, `&T`, or `&mut T` can be passed directly to this function
160/// as they implicitly coerce to `*const T`.
161///
162/// # Example
163///
164/// ```
165/// use ptr_meta::metadata;
166///
167/// assert_eq!(metadata("foo"), 3_usize);
168/// ```
169pub fn metadata<T: Pointee + ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
170    unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
171}
172
173/// Forms a (possibly-wide) raw pointer from a data address and metadata.
174///
175/// This function is safe but the returned pointer is not necessarily safe to dereference.
176/// For slices, see the documentation of [`slice::from_raw_parts`] for safety requirements.
177/// For trait objects, the metadata must come from a pointer to the same underlying ereased type.
178///
179/// [`slice::from_raw_parts`]: core::slice::from_raw_parts
180pub fn from_raw_parts<T: Pointee + ?Sized>(data_address: *const (), metadata: <T as Pointee>::Metadata) -> *const T {
181    unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
182}
183
184/// Performs the same functionality as [`from_raw_parts`], except that a
185/// raw `*mut` pointer is returned, as opposed to a raw `*const` pointer.
186///
187/// See the documentation of [`from_raw_parts`] for more details.
188pub fn from_raw_parts_mut<T: Pointee + ?Sized>(data_address: *mut (), metadata: <T as Pointee>::Metadata) -> *mut T {
189    unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
190}
191
192/// Extension methods for [`NonNull`](core::ptr::NonNull).
193pub trait NonNullExt<T: Pointee + ?Sized> {
194    /// The type's raw pointer (`NonNull<()>`).
195    type Raw;
196
197    /// Creates a new non-null pointer from its raw parts.
198    fn from_raw_parts(raw: Self::Raw, meta: <T as Pointee>::Metadata) -> Self;
199    /// Converts a non-null pointer to its raw parts.
200    fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata);
201}
202
203impl<T: Pointee + ?Sized> NonNullExt<T> for ptr::NonNull<T> {
204    type Raw = ptr::NonNull<()>;
205
206    fn from_raw_parts(raw: Self::Raw, meta: <T as Pointee>::Metadata) -> Self {
207        unsafe { Self::new_unchecked(from_raw_parts_mut(raw.as_ptr(), meta)) }
208    }
209
210    fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
211        let (raw, meta) = PtrExt::to_raw_parts(self.as_ptr());
212        unsafe { (ptr::NonNull::new_unchecked(raw), meta) }
213    }
214}
215
216/// Extension methods for pointers.
217pub trait PtrExt<T: Pointee + ?Sized> {
218    /// The type's raw pointer (`*const ()` or `*mut ()`).
219    type Raw;
220
221    /// Decompose a (possibly wide) pointer into its address and metadata
222    /// components.
223    ///
224    /// The pointer can be later reconstructed with [`from_raw_parts`].
225    fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata);
226}
227
228impl<T: Pointee + ?Sized> PtrExt<T> for *const T {
229    type Raw = *const ();
230
231    fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
232        unsafe { (&self as *const Self).cast::<(Self::Raw, <T as Pointee>::Metadata)>().read() }
233    }
234}
235
236impl<T: Pointee + ?Sized> PtrExt<T> for *mut T {
237    type Raw = *mut ();
238
239    fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
240        unsafe { (&self as *const Self).cast::<(Self::Raw, <T as Pointee>::Metadata)>().read() }
241    }
242}
243
244/// The metadata for a `Dyn = dyn SomeTrait` trait object type.
245///
246/// It is a pointer to a vtable (virtual call table)
247/// that represents all the necessary information
248/// to manipulate the concrete type stored inside a trait object.
249/// The vtable notably it contains:
250///
251/// * type size
252/// * type alignment
253/// * a pointer to the type’s `drop_in_place` impl (may be a no-op for plain-old-data)
254/// * pointers to all the methods for the type’s implementation of the trait
255///
256/// Note that the first three are special because they’re necessary to allocate, drop,
257/// and deallocate any trait object.
258///
259/// It is possible to name this struct with a type parameter that is not a `dyn` trait object
260/// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
261#[repr(transparent)]
262pub struct DynMetadata<Dyn: ?Sized> {
263    vtable_ptr: &'static VTable,
264    phantom: PhantomData<Dyn>,
265}
266
267#[repr(C)]
268struct VTable {
269    drop_in_place: fn(*mut ()),
270    size_of: usize,
271    align_of: usize,
272}
273
274impl<Dyn: ?Sized> DynMetadata<Dyn> {
275    /// Returns the size of the type associated with this vtable.
276    pub fn size_of(self) -> usize {
277        self.vtable_ptr.size_of
278    }
279
280    /// Returns the alignment of the type associated with this vtable.
281    pub fn align_of(self) -> usize {
282        self.vtable_ptr.align_of
283    }
284
285    /// Returns the size and alignment together as a `Layout`.
286    pub fn layout(self) -> Layout {
287        unsafe { Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
288    }
289}
290
291unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
292unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
293impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
294    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295        f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
296    }
297}
298impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
299impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
300impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
301    #[inline]
302    fn clone(&self) -> Self {
303        *self
304    }
305}
306impl<Dyn: ?Sized> cmp::Eq for DynMetadata<Dyn> {}
307impl<Dyn: ?Sized> cmp::PartialEq for DynMetadata<Dyn> {
308    #[inline]
309    fn eq(&self, other: &Self) -> bool {
310        ptr::eq(self.vtable_ptr, other.vtable_ptr)
311    }
312}
313impl<Dyn: ?Sized> cmp::Ord for DynMetadata<Dyn> {
314    #[inline]
315    fn cmp(&self, other: &Self) -> cmp::Ordering {
316        (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
317    }
318}
319impl<Dyn: ?Sized> cmp::PartialOrd for DynMetadata<Dyn> {
320    #[inline]
321    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
322        Some(self.cmp(other))
323    }
324}
325impl<Dyn: ?Sized> hash::Hash for DynMetadata<Dyn> {
326    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
327        ptr::hash(self.vtable_ptr, hasher)
328    }
329}
330
331#[cfg(test)]
332mod tests {
333    use crate as ptr_meta;
334    use super::{from_raw_parts, pointee, Pointee, PtrExt};
335
336    fn test_pointee<T: Pointee + ?Sized>(value: &T) {
337        let ptr = value as *const T;
338        let (raw, meta) = PtrExt::to_raw_parts(ptr);
339        let re_ptr = from_raw_parts::<T>(raw, meta);
340        assert_eq!(ptr, re_ptr);
341    }
342
343    #[test]
344    fn sized_types() {
345        test_pointee(&());
346        test_pointee(&42);
347        test_pointee(&true);
348        test_pointee(&[1, 2, 3, 4]);
349
350        struct TestUnit;
351
352        test_pointee(&TestUnit);
353
354        #[allow(dead_code)]
355        struct TestStruct {
356            a: (),
357            b: i32,
358            c: bool,
359        }
360
361        test_pointee(&TestStruct { a: (), b: 42, c: true });
362
363        struct TestTuple((), i32, bool);
364
365        test_pointee(&TestTuple((), 42, true));
366
367        struct TestGeneric<T>(T);
368
369        test_pointee(&TestGeneric(42));
370    }
371
372    #[test]
373    fn unsized_types() {
374        test_pointee("hello world");
375        test_pointee(&[1, 2, 3, 4] as &[i32]);
376    }
377
378    #[test]
379    fn trait_objects() {
380        #[pointee]
381        trait TestTrait {
382            fn foo(&self);
383        }
384
385        struct A;
386
387        impl TestTrait for A {
388            fn foo(&self) {}
389        }
390
391        let trait_object = &A as &dyn TestTrait;
392
393        test_pointee(trait_object);
394
395        let (_, meta) = PtrExt::to_raw_parts(trait_object as *const dyn TestTrait);
396
397        assert_eq!(meta.size_of(), 0);
398        assert_eq!(meta.align_of(), 1);
399
400        struct B(i32);
401
402        impl TestTrait for B {
403            fn foo(&self) {}
404        }
405
406        let b = B(42);
407        let trait_object = &b as &dyn TestTrait;
408
409        test_pointee(trait_object);
410
411        let (_, meta) = PtrExt::to_raw_parts(trait_object as *const dyn TestTrait);
412
413        assert_eq!(meta.size_of(), 4);
414        assert_eq!(meta.align_of(), 4);
415    }
416
417    #[test]
418    fn last_field_dst() {
419        #[allow(dead_code)]
420        #[derive(Pointee)]
421        struct Test<H, T> {
422            head: H,
423            tail: [T],
424        }
425
426        #[allow(dead_code)]
427        #[derive(Pointee)]
428        struct TestDyn {
429            tail: dyn core::any::Any,
430        }
431
432        #[pointee]
433        trait TestTrait {}
434
435        #[allow(dead_code)]
436        #[derive(Pointee)]
437        struct TestCustomDyn {
438            tail: dyn TestTrait,
439        }
440    }
441}