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 
55 mod impls;
56 
57 use core::{alloc::Layout, cmp, fmt, hash, marker::PhantomData, ptr};
58 
59 pub 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
109 pub 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 
114 impl<T> Pointee for T {
115     type Metadata = ();
116 }
117 
118 impl<T> Pointee for [T] {
119     type Metadata = usize;
120 }
121 
122 impl Pointee for str {
123     type Metadata = usize;
124 }
125 
126 #[cfg(feature = "std")]
127 impl Pointee for ::std::ffi::CStr {
128     type Metadata = usize;
129 }
130 
131 #[cfg(feature = "std")]
132 impl Pointee for ::std::ffi::OsStr {
133     type Metadata = usize;
134 }
135 
136 #[repr(C)]
137 pub(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)]
144 pub(crate) struct PtrComponents<T: Pointee + ?Sized> {
145     pub(crate) data_address: *const (),
146     pub(crate) metadata: <T as Pointee>::Metadata,
147 }
148 
149 impl<T: Pointee + ?Sized> Clone for PtrComponents<T> {
clone(&self) -> Self150     fn clone(&self) -> Self {
151         Self {
152             data_address: self.data_address.clone(),
153             metadata: self.metadata.clone(),
154         }
155     }
156 }
157 
158 impl<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 /// ```
metadata<T: Pointee + ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata172 pub 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
from_raw_parts<T: Pointee + ?Sized>( data_address: *const (), metadata: <T as Pointee>::Metadata, ) -> *const T183 pub 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.
from_raw_parts_mut<T: Pointee + ?Sized>( data_address: *mut (), metadata: <T as Pointee>::Metadata, ) -> *mut T202 pub 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).
218 pub trait NonNullExt<T: Pointee + ?Sized> {
219     /// Creates a new non-null pointer from its raw parts.
from_raw_parts(raw: ptr::NonNull<()>, meta: <T as Pointee>::Metadata) -> Self220     fn from_raw_parts(raw: ptr::NonNull<()>, meta: <T as Pointee>::Metadata) -> Self;
221     /// Converts a non-null pointer to its raw parts.
to_raw_parts(self) -> (ptr::NonNull<()>, <T as Pointee>::Metadata)222     fn to_raw_parts(self) -> (ptr::NonNull<()>, <T as Pointee>::Metadata);
223 }
224 
225 impl<T: Pointee + ?Sized> NonNullExt<T> for ptr::NonNull<T> {
from_raw_parts(raw: ptr::NonNull<()>, meta: <T as Pointee>::Metadata) -> Self226     fn from_raw_parts(raw: ptr::NonNull<()>, meta: <T as Pointee>::Metadata) -> Self {
227         unsafe { Self::new_unchecked(from_raw_parts_mut(raw.as_ptr(), meta)) }
228     }
229 
to_raw_parts(self) -> (ptr::NonNull<()>, <T as Pointee>::Metadata)230     fn to_raw_parts(self) -> (ptr::NonNull<()>, <T as Pointee>::Metadata) {
231         let (raw, meta) = PtrExt::to_raw_parts(self.as_ptr());
232         unsafe { (ptr::NonNull::new_unchecked(raw), meta) }
233     }
234 }
235 
236 /// Extension methods for pointers.
237 pub 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`].
to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata)244     fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata);
245 }
246 
247 impl<T: Pointee + ?Sized> PtrExt<T> for *const T {
248     type Raw = *const ();
249 
to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata)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 
259 impl<T: Pointee + ?Sized> PtrExt<T> for *mut T {
260     type Raw = *mut ();
261 
to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata)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)]
287 pub struct DynMetadata<Dyn: ?Sized> {
288     vtable_ptr: &'static VTable,
289     phantom: PhantomData<Dyn>,
290 }
291 
292 #[repr(C)]
293 struct VTable {
294     drop_in_place: fn(*mut ()),
295     size_of: usize,
296     align_of: usize,
297 }
298 
299 impl<Dyn: ?Sized> DynMetadata<Dyn> {
300     /// Returns the size of the type associated with this vtable.
size_of(self) -> usize301     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.
align_of(self) -> usize306     pub fn align_of(self) -> usize {
307         self.vtable_ptr.align_of
308     }
309 
310     /// Returns the size and alignment together as a `Layout`.
layout(self) -> Layout311     pub fn layout(self) -> Layout {
312         unsafe { Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
313     }
314 }
315 
316 unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
317 unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
318 impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result319     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320         f.debug_tuple("DynMetadata")
321             .field(&(self.vtable_ptr as *const VTable))
322             .finish()
323     }
324 }
325 impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
326 impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
327 impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
328     #[inline]
clone(&self) -> Self329     fn clone(&self) -> Self {
330         *self
331     }
332 }
333 impl<Dyn: ?Sized> cmp::Eq for DynMetadata<Dyn> {}
334 impl<Dyn: ?Sized> cmp::PartialEq for DynMetadata<Dyn> {
335     #[inline]
eq(&self, other: &Self) -> bool336     fn eq(&self, other: &Self) -> bool {
337         ptr::eq(self.vtable_ptr, other.vtable_ptr)
338     }
339 }
340 impl<Dyn: ?Sized> cmp::Ord for DynMetadata<Dyn> {
341     #[inline]
cmp(&self, other: &Self) -> cmp::Ordering342     fn cmp(&self, other: &Self) -> cmp::Ordering {
343         (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
344     }
345 }
346 impl<Dyn: ?Sized> cmp::PartialOrd for DynMetadata<Dyn> {
347     #[inline]
partial_cmp(&self, other: &Self) -> Option<cmp::Ordering>348     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
349         Some(self.cmp(other))
350     }
351 }
352 impl<Dyn: ?Sized> hash::Hash for DynMetadata<Dyn> {
hash<H: hash::Hasher>(&self, hasher: &mut H)353     fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
354         ptr::hash(self.vtable_ptr, hasher)
355     }
356 }
357 
358 #[cfg(test)]
359 mod tests {
360     use super::{from_raw_parts, pointee, Pointee, PtrExt};
361     use crate as ptr_meta;
362 
test_pointee<T: Pointee + ?Sized>(value: &T)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]
sized_types()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]
unsized_types()404     fn unsized_types() {
405         test_pointee("hello world");
406         test_pointee(&[1, 2, 3, 4] as &[i32]);
407     }
408 
409     #[test]
trait_objects()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]
last_field_dst()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