ptr_meta/
lib.rs

1//! A radioactive stabilization of the [`ptr_meta` RFC][rfc].
2//!
3//! This crate provides the [`Pointee`] trait, [`from_raw_parts`] and
4//! [`to_raw_parts`] functions, and proc macros for deriving `Pointee` for
5//! structs and implementing `Pointee` for trait objects.
6//!
7//! [rfc]: https://rust-lang.github.io/rfcs/2580-ptr-meta.html
8//!
9//! # Usage
10//!
11//! Raw pointers can be decomposed into the data address and metadata components
12//! with [`to_raw_parts`] or [`to_raw_parts_mut`].
13//!
14//! Alternatively, metadata alone can be extracted with the [`metadata`]
15//! function. Although [`metadata`] accepts pointers, references can be passed
16//! and will be implicitly coerced.
17//!
18//! A pointer can be created from its address and metadata with
19//! [`from_raw_parts`] or [`from_raw_parts_mut`].
20//!
21//! ## Provided impls
22//!
23//! `ptr_meta` provides inherent implementations for many builtin types:
24//!
25//! - All [`Sized`] types implement [`Pointee`] via a blanket implementation.
26//! - `slice`, `str`, and `CStr`
27//! - `OsStr` (requires `std`)
28//! - `dyn Any`, optionally with `+ Send` and/or `+ Sync`
29//! - `dyn Error`, optionally with `+ Send` and/or `+ Sync`
30//!
31//! ## Structs with trailing DSTs
32//!
33//! You can derive [`Pointee`] for structs with trailing DSTs:
34//!
35//! ```
36//! use ptr_meta::Pointee;
37//!
38//! #[derive(Pointee)]
39//! struct Block<H, T> {
40//!     header: H,
41//!     elements: [T],
42//! }
43//! ```
44//!
45//! Note that the last field is required to be a DST. Structs with a generic
46//! type as the last field may have conflicting blanket implementations, as the
47//! generic type may be `Sized`. A collection of specific implementations may be
48//! required in these cases, with the generic parameter set (for example) a
49//! slice, `str`, or specific trait object.
50//!
51//! ## Trait objects
52//!
53//! You can generate [`Pointee`] implementations for trait objects:
54//!
55//! ```
56//! use ptr_meta::pointee;
57//!
58//! // Generates Pointee for dyn Stringy
59//! #[ptr_meta::pointee]
60//! trait Stringy {
61//!     fn as_string(&self) -> String;
62//! }
63//! ```
64//!
65//! Note that this will not produce implementations for `Trait + Send + Sync`.
66//!
67//! ## Features
68//!
69//! - `derive`: Re-exports the macros from `ptr_meta_derive`. Enabled by
70//!   default.
71//! - `std`: Enables additional impls for `std` types. Enabled by default.
72//!
73//! ## Example
74#![doc = include_str!("../example.md")]
75#![deny(
76    future_incompatible,
77    missing_docs,
78    nonstandard_style,
79    unsafe_op_in_unsafe_fn,
80    unused,
81    warnings,
82    clippy::all,
83    clippy::missing_safety_doc,
84    clippy::undocumented_unsafe_blocks,
85    rustdoc::broken_intra_doc_links,
86    rustdoc::missing_crate_level_docs
87)]
88#![cfg_attr(not(feature = "std"), no_std)]
89#![cfg_attr(all(docsrs, not(doctest)), feature(doc_cfg, doc_auto_cfg))]
90#![cfg_attr(miri, allow(internal_features), feature(core_intrinsics))]
91
92mod impls;
93
94use core::{
95    ffi::CStr,
96    fmt,
97    hash::{Hash, Hasher},
98};
99
100#[cfg(feature = "derive")]
101pub use ptr_meta_derive::{pointee, Pointee};
102
103/// A trait which associates pointer metadata with a pointee type.
104///
105/// # Pointer metadata
106///
107/// Pointers and references can be thought of as having two parts: a data
108/// address and some extra "pointer metadata".
109///
110/// Pointers to [statically-sized types](`Sized`) and `extern` types are
111/// "narrow": their pointer metadata is `()`.
112///
113/// Pointers to [dynamically-sized types][dst] are "wide": they have pointer
114/// metadata with a non-zero size. There are four classes of dynamically-sized
115/// types currently available:
116///
117/// * `str`s have `usize` pointer metadata equal to the length of the string
118///   slice in bytes.
119/// * Slices like `[i32]` have `usize` pointer metadata equal to the length of
120///   the slice in items.
121/// * Trait objects like `dyn SomeTrait` have [`DynMetadata`] pointer metadata,
122///   which point to the trait objects' virtual method tables.
123/// * Structs with a trailing DST have the same metadata as the trailing DST.
124///
125/// In the future, Rust may add new kinds of types which have different pointer
126/// metadata.
127///
128/// [dst]: https://doc.rust-lang.org/reference/dynamically-sized-types.html
129///
130/// # Safety
131///
132/// The associated `Metadata` type must be the pointer metadata type for the
133/// implementing type.
134pub unsafe trait Pointee {
135    /// The metadata type for pointers and references to this type.
136    type Metadata: Copy + Send + Sync + Ord + Hash + Unpin;
137}
138
139// SAFETY: Pointers to `Sized` types have no metadata (i.e. their metadata is
140// the unit type `()`).
141unsafe impl<T> Pointee for T {
142    type Metadata = ();
143}
144
145// SAFETY: Pointers to slices have a `usize` representing the length of the
146// slice in elements as their metadata.
147unsafe impl<T> Pointee for [T] {
148    type Metadata = usize;
149}
150
151// SAFETY: String slice pointers have a `usize` representing the length of the
152// string slice in bytes as their metadata.
153unsafe impl Pointee for str {
154    type Metadata = usize;
155}
156
157// SAFETY: `CStr` pointers have a `usize` representing the length of the
158// C-string slice in bytes (nul included) as their metadata.
159unsafe impl Pointee for CStr {
160    type Metadata = usize;
161}
162
163#[cfg(feature = "std")]
164// SAFETY: `OsStr` pointers have a `usize` representing the length of the
165// string in bytes as their metadata.
166unsafe impl Pointee for std::ffi::OsStr {
167    type Metadata = usize;
168}
169
170/// Returns the metadata of the given pointer.
171///
172/// `*mut T`, `&T`, and `&mut T` can all be passed directly to this function as
173/// they implicitly coerce to `*const T`.
174///
175/// # Example
176///
177/// ```
178/// // String slices have pointer metadata equal to their size in bytes
179/// assert_eq!(ptr_meta::metadata("foo"), 3_usize);
180/// ```
181#[inline]
182pub const fn metadata<T: Pointee + ?Sized>(
183    ptr: *const T,
184) -> <T as Pointee>::Metadata {
185    // SAFETY: Accessing the value from the `PtrRepr` union is safe since
186    // *const T and PtrComponents<T> have the same memory layouts. Only std can
187    // make this guarantee.
188    unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
189}
190
191/// Returns the data address and metadata of the given pointer.
192///
193/// `*mut T`, `&T`, and `&mut T` can all be passed directly to this function as
194/// they implicitly coerce to `*const T`.
195///
196/// # Example
197///
198/// ```
199/// let (data_address, metadata) = ptr_meta::to_raw_parts("foo");
200/// assert_ne!(data_address, core::ptr::null());
201/// assert_eq!(metadata, 3);
202/// ```
203#[inline]
204pub const fn to_raw_parts<T: Pointee + ?Sized>(
205    ptr: *const T,
206) -> (*const (), <T as Pointee>::Metadata) {
207    (ptr as *const (), metadata(ptr))
208}
209
210/// Returns the mutable data address and metadata of the given pointer.
211///
212/// See [`to_raw_parts`] for more details.
213#[inline]
214pub const fn to_raw_parts_mut<T: Pointee + ?Sized>(
215    ptr: *mut T,
216) -> (*mut (), <T as Pointee>::Metadata) {
217    (ptr as *mut (), metadata(ptr))
218}
219
220/// Returns a raw pointer with the given data address and metadata.
221///
222/// This function is safe, but the returned pointer is not necessarily safe to
223/// dereference. For slices, see the documentation of [`slice::from_raw_parts`]
224/// for safety requirements. For trait objects, the metadata must come from a
225/// a trait object with the same underlying type.
226///
227/// [`slice::from_raw_parts`]: core::slice::from_raw_parts
228#[inline]
229pub const fn from_raw_parts<T: Pointee + ?Sized>(
230    data_address: *const (),
231    metadata: <T as Pointee>::Metadata,
232) -> *const T {
233    // SAFETY: Accessing the value from the `PtrRepr` union is safe since
234    // *const T and PtrComponents<T> have the same memory layouts. Only std can
235    // make this guarantee.
236    unsafe {
237        PtrRepr {
238            components: PtrComponents {
239                data_address,
240                metadata,
241            },
242        }
243        .const_ptr
244    }
245}
246
247/// Returns a mutable raw pointer with the given data address and metadata.
248///
249/// See [`from_raw_parts`] for more details.
250#[inline]
251pub const fn from_raw_parts_mut<T: Pointee + ?Sized>(
252    data_address: *mut (),
253    metadata: <T as Pointee>::Metadata,
254) -> *mut T {
255    // SAFETY: Accessing the value from the `PtrRepr` union is safe since
256    // *const T and PtrComponents<T> have the same memory layouts. Only std can
257    // make this guarantee.
258    unsafe {
259        PtrRepr {
260            components: PtrComponents {
261                data_address,
262                metadata,
263            },
264        }
265        .mut_ptr
266    }
267}
268
269#[repr(C)]
270union PtrRepr<T: Pointee + ?Sized> {
271    const_ptr: *const T,
272    mut_ptr: *mut T,
273    components: PtrComponents<T>,
274}
275
276#[repr(C)]
277struct PtrComponents<T: Pointee + ?Sized> {
278    data_address: *const (),
279    metadata: <T as Pointee>::Metadata,
280}
281
282// Manual impl needed to avoid `T: Copy` bound.
283impl<T: Pointee + ?Sized> Copy for PtrComponents<T> {}
284
285// Manual impl needed to avoid `T: Clone` bound.
286impl<T: Pointee + ?Sized> Clone for PtrComponents<T> {
287    fn clone(&self) -> Self {
288        *self
289    }
290}
291
292/// The metadata for a trait object.
293///
294/// This struct wraps a pointer to a vtable (virtual method table) which
295/// contains all of the necessary information to manipulate the concrete type
296/// stored inside of the trait object:
297///
298/// * The size and alignment of the concrete type
299/// * A function pointer to the type's `drop_in_place` impl
300/// * Function pointers for each method in the concrete type's trait
301///   implementation
302///
303/// Providing a type argument that is not a `dyn` trait object is possible, but
304/// does not correspond with a meaningful type.
305pub struct DynMetadata<Dyn: ?Sized> {
306    vtable_ptr: &'static VTable,
307    phantom: core::marker::PhantomData<Dyn>,
308}
309
310// Extern types are not stable, so we substitute a ZST. This is not a perfect
311// substitute but it's not exposed anywhere so it's close enough.
312struct VTable;
313
314impl<Dyn: ?Sized> DynMetadata<Dyn> {
315    /// Returns the size of the type associated with this metadata.
316    #[inline]
317    pub fn size_of(self) -> usize {
318        #[cfg(miri)]
319        {
320            // Note that "size stored in vtable" is *not* the same as "result of
321            // size_of_val_raw". Consider a reference like `&(i32,
322            // dyn Send)`: the vtable will only store the size of the
323            // `Send` part!
324            // SAFETY: DynMetadata always contains a valid vtable pointer
325            return unsafe {
326                core::intrinsics::vtable_size(
327                    self.vtable_ptr as *const VTable as *const (),
328                )
329            };
330        }
331        #[cfg(not(miri))]
332        {
333            // SAFETY: This happens to be true. It may not always be true. The
334            // location of the size for vtables is based on the implementation
335            // of the vtable_size intrinsic.
336            unsafe {
337                (self.vtable_ptr as *const VTable as *const usize)
338                    .add(1)
339                    .read()
340            }
341        }
342    }
343
344    /// Returns the alignment of the type associated with this metadata.
345    #[inline]
346    pub fn align_of(self) -> usize {
347        #[cfg(miri)]
348        {
349            // SAFETY: DynMetadata always contains a valid vtable pointer
350            return unsafe {
351                core::intrinsics::vtable_align(
352                    self.vtable_ptr as *const VTable as *const (),
353                )
354            };
355        }
356        #[cfg(not(miri))]
357        {
358            // SAFETY: This happens to be true. It may not always be true. The
359            // location of the alignment for vtables is based on the
360            // implementation of the vtable_align intrinsic.
361            unsafe {
362                (self.vtable_ptr as *const VTable as *const usize)
363                    .add(2)
364                    .read()
365            }
366        }
367    }
368
369    /// Returns the layout of the type associated with this metadata.
370    #[inline]
371    pub fn layout(self) -> core::alloc::Layout {
372        // SAFETY: the compiler emitted this vtable for a concrete Rust type
373        // which is known to have a valid layout. Same rationale as in
374        // `Layout::for_value`.
375        unsafe {
376            core::alloc::Layout::from_size_align_unchecked(
377                self.size_of(),
378                self.align_of(),
379            )
380        }
381    }
382}
383
384// SAFETY: References to trait object vtables are guaranteed to be `Send`.
385unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
386// SAFETY: References to trait object vtables are guaranteed to be `Sync`.
387unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
388
389impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        f.debug_tuple("DynMetadata")
392            .field(&(self.vtable_ptr as *const VTable))
393            .finish()
394    }
395}
396
397// Manual impls needed to avoid `Dyn: $Trait` bounds.
398
399impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
400
401impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
402
403impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
404    #[inline]
405    fn clone(&self) -> Self {
406        *self
407    }
408}
409
410impl<Dyn: ?Sized> Eq for DynMetadata<Dyn> {}
411
412impl<Dyn: ?Sized> PartialEq for DynMetadata<Dyn> {
413    #[inline]
414    fn eq(&self, other: &Self) -> bool {
415        core::ptr::eq::<VTable>(self.vtable_ptr, other.vtable_ptr)
416    }
417}
418
419impl<Dyn: ?Sized> Ord for DynMetadata<Dyn> {
420    #[inline]
421    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
422        (self.vtable_ptr as *const VTable)
423            .cmp(&(other.vtable_ptr as *const VTable))
424    }
425}
426
427impl<Dyn: ?Sized> PartialOrd for DynMetadata<Dyn> {
428    #[inline]
429    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
430        Some(self.cmp(other))
431    }
432}
433
434impl<Dyn: ?Sized> Hash for DynMetadata<Dyn> {
435    #[inline]
436    fn hash<H: Hasher>(&self, hasher: &mut H) {
437        core::ptr::hash::<VTable, _>(self.vtable_ptr, hasher)
438    }
439}
440
441#[cfg(test)]
442fn test_pointee<T: Pointee + ?Sized>(value: &T) {
443    let ptr = value as *const T;
444    let (raw, meta) = to_raw_parts(ptr);
445    let re_ptr = from_raw_parts::<T>(raw, meta);
446    assert_eq!(ptr, re_ptr);
447}
448
449#[cfg(test)]
450mod tests {
451    use super::test_pointee;
452
453    #[test]
454    fn sized_types() {
455        test_pointee(&());
456        test_pointee(&42);
457        test_pointee(&true);
458        test_pointee(&[1, 2, 3, 4]);
459
460        struct TestUnit;
461
462        test_pointee(&TestUnit);
463
464        #[allow(dead_code)]
465        struct TestStruct {
466            a: (),
467            b: i32,
468            c: bool,
469        }
470
471        test_pointee(&TestStruct {
472            a: (),
473            b: 42,
474            c: true,
475        });
476
477        #[allow(dead_code)]
478        struct TestTuple((), i32, bool);
479
480        test_pointee(&TestTuple((), 42, true));
481
482        struct TestGeneric<T>(T);
483
484        test_pointee(&TestGeneric(42));
485    }
486
487    #[test]
488    fn unsized_types() {
489        test_pointee("hello world");
490        test_pointee(&[1, 2, 3, 4] as &[i32]);
491    }
492}
493
494#[cfg(all(test, feature = "derive"))]
495mod derive_tests {
496    use core::any::Any;
497
498    use super::{test_pointee, Pointee};
499
500    #[test]
501    fn trait_objects() {
502        #[crate::pointee(crate)]
503        trait TestTrait {
504            #[allow(dead_code)]
505            fn foo(&self);
506        }
507
508        struct A;
509
510        impl TestTrait for A {
511            fn foo(&self) {}
512        }
513
514        let trait_object = &A as &dyn TestTrait;
515
516        test_pointee(trait_object);
517
518        #[allow(dead_code)]
519        struct B(i32);
520
521        impl TestTrait for B {
522            fn foo(&self) {}
523        }
524
525        let b = B(42);
526        let trait_object = &b as &dyn TestTrait;
527
528        test_pointee(trait_object);
529    }
530
531    #[test]
532    fn last_field_dst() {
533        #[allow(dead_code)]
534        #[derive(Pointee)]
535        #[ptr_meta(crate)]
536        struct Test<H, T> {
537            head: H,
538            tail: [T],
539        }
540
541        #[allow(dead_code)]
542        #[derive(Pointee)]
543        #[ptr_meta(crate)]
544        struct TestDyn {
545            tail: dyn Any,
546        }
547
548        #[crate::pointee(crate)]
549        trait TestTrait {}
550
551        #[allow(dead_code)]
552        #[derive(Pointee)]
553        #[ptr_meta(crate)]
554        struct TestCustomDyn {
555            tail: dyn TestTrait,
556        }
557    }
558
559    #[test]
560    fn generic_trait() {
561        #[allow(dead_code)]
562        #[crate::pointee(crate)]
563        trait TestTrait<T: ?Sized> {}
564
565        impl<T: ?Sized> TestTrait<T> for () {}
566
567        test_pointee(&() as &dyn TestTrait<u32>);
568    }
569}