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}