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> { |
150 | 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 | /// ``` |
172 | 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 |
183 | 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. |
202 | 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. |
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 | |
225 | impl<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. |
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`]. |
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 | |
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 | |
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. |
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 | |
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> { |
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 | } |
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 ] |
329 | 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 ] |
336 | fn eq(&self, other: &Self) -> bool { |
337 | ptr::eq(self.vtable_ptr, b:other.vtable_ptr) |
338 | } |
339 | } |
340 | impl<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 | } |
346 | impl<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 | } |
352 | impl<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)] |
359 | mod 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 | |