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