1#![cfg_attr(not(feature = "std"), no_std)]
46
47mod impls;
48
49use core::{
50 alloc::Layout,
51 cmp,
52 fmt,
53 hash,
54 marker::PhantomData,
55 ptr,
56};
57
58pub use ptr_meta_derive::{pointee, Pointee};
59
60pub trait Pointee {
107 type Metadata: Copy + Send + Sync + Ord + hash::Hash + Unpin;
109}
110
111impl<T> Pointee for T {
112 type Metadata = ();
113}
114
115impl<T> Pointee for [T] {
116 type Metadata = usize;
117}
118
119impl Pointee for str {
120 type Metadata = usize;
121}
122
123#[cfg(feature = "std")]
124impl Pointee for ::std::ffi::CStr {
125 type Metadata = usize;
126}
127
128#[cfg(feature = "std")]
129impl Pointee for ::std::ffi::OsStr {
130 type Metadata = usize;
131}
132
133#[repr(C)]
134pub(crate) union PtrRepr<T: Pointee + ?Sized> {
135 pub(crate) const_ptr: *const T,
136 pub(crate) mut_ptr: *mut T,
137 pub(crate) components: PtrComponents<T>,
138}
139
140#[repr(C)]
141pub(crate) struct PtrComponents<T: Pointee + ?Sized> {
142 pub(crate) data_address: *const (),
143 pub(crate) metadata: <T as Pointee>::Metadata,
144}
145
146impl<T: Pointee + ?Sized> Clone for PtrComponents<T> {
147 fn clone(&self) -> Self {
148 Self {
149 data_address: self.data_address.clone(),
150 metadata: self.metadata.clone(),
151 }
152 }
153}
154
155impl<T: Pointee + ?Sized> Copy for PtrComponents<T> {}
156
157pub fn metadata<T: Pointee + ?Sized>(ptr: *const T) -> <T as Pointee>::Metadata {
170 unsafe { PtrRepr { const_ptr: ptr }.components.metadata }
171}
172
173pub fn from_raw_parts<T: Pointee + ?Sized>(data_address: *const (), metadata: <T as Pointee>::Metadata) -> *const T {
181 unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr }
182}
183
184pub fn from_raw_parts_mut<T: Pointee + ?Sized>(data_address: *mut (), metadata: <T as Pointee>::Metadata) -> *mut T {
189 unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.mut_ptr }
190}
191
192pub trait NonNullExt<T: Pointee + ?Sized> {
194 type Raw;
196
197 fn from_raw_parts(raw: Self::Raw, meta: <T as Pointee>::Metadata) -> Self;
199 fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata);
201}
202
203impl<T: Pointee + ?Sized> NonNullExt<T> for ptr::NonNull<T> {
204 type Raw = ptr::NonNull<()>;
205
206 fn from_raw_parts(raw: Self::Raw, meta: <T as Pointee>::Metadata) -> Self {
207 unsafe { Self::new_unchecked(from_raw_parts_mut(raw.as_ptr(), meta)) }
208 }
209
210 fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
211 let (raw, meta) = PtrExt::to_raw_parts(self.as_ptr());
212 unsafe { (ptr::NonNull::new_unchecked(raw), meta) }
213 }
214}
215
216pub trait PtrExt<T: Pointee + ?Sized> {
218 type Raw;
220
221 fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata);
226}
227
228impl<T: Pointee + ?Sized> PtrExt<T> for *const T {
229 type Raw = *const ();
230
231 fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
232 unsafe { (&self as *const Self).cast::<(Self::Raw, <T as Pointee>::Metadata)>().read() }
233 }
234}
235
236impl<T: Pointee + ?Sized> PtrExt<T> for *mut T {
237 type Raw = *mut ();
238
239 fn to_raw_parts(self) -> (Self::Raw, <T as Pointee>::Metadata) {
240 unsafe { (&self as *const Self).cast::<(Self::Raw, <T as Pointee>::Metadata)>().read() }
241 }
242}
243
244#[repr(transparent)]
262pub struct DynMetadata<Dyn: ?Sized> {
263 vtable_ptr: &'static VTable,
264 phantom: PhantomData<Dyn>,
265}
266
267#[repr(C)]
268struct VTable {
269 drop_in_place: fn(*mut ()),
270 size_of: usize,
271 align_of: usize,
272}
273
274impl<Dyn: ?Sized> DynMetadata<Dyn> {
275 pub fn size_of(self) -> usize {
277 self.vtable_ptr.size_of
278 }
279
280 pub fn align_of(self) -> usize {
282 self.vtable_ptr.align_of
283 }
284
285 pub fn layout(self) -> Layout {
287 unsafe { Layout::from_size_align_unchecked(self.size_of(), self.align_of()) }
288 }
289}
290
291unsafe impl<Dyn: ?Sized> Send for DynMetadata<Dyn> {}
292unsafe impl<Dyn: ?Sized> Sync for DynMetadata<Dyn> {}
293impl<Dyn: ?Sized> fmt::Debug for DynMetadata<Dyn> {
294 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
295 f.debug_tuple("DynMetadata").field(&(self.vtable_ptr as *const VTable)).finish()
296 }
297}
298impl<Dyn: ?Sized> Unpin for DynMetadata<Dyn> {}
299impl<Dyn: ?Sized> Copy for DynMetadata<Dyn> {}
300impl<Dyn: ?Sized> Clone for DynMetadata<Dyn> {
301 #[inline]
302 fn clone(&self) -> Self {
303 *self
304 }
305}
306impl<Dyn: ?Sized> cmp::Eq for DynMetadata<Dyn> {}
307impl<Dyn: ?Sized> cmp::PartialEq for DynMetadata<Dyn> {
308 #[inline]
309 fn eq(&self, other: &Self) -> bool {
310 ptr::eq(self.vtable_ptr, other.vtable_ptr)
311 }
312}
313impl<Dyn: ?Sized> cmp::Ord for DynMetadata<Dyn> {
314 #[inline]
315 fn cmp(&self, other: &Self) -> cmp::Ordering {
316 (self.vtable_ptr as *const VTable).cmp(&(other.vtable_ptr as *const VTable))
317 }
318}
319impl<Dyn: ?Sized> cmp::PartialOrd for DynMetadata<Dyn> {
320 #[inline]
321 fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
322 Some(self.cmp(other))
323 }
324}
325impl<Dyn: ?Sized> hash::Hash for DynMetadata<Dyn> {
326 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
327 ptr::hash(self.vtable_ptr, hasher)
328 }
329}
330
331#[cfg(test)]
332mod tests {
333 use crate as ptr_meta;
334 use super::{from_raw_parts, pointee, Pointee, PtrExt};
335
336 fn test_pointee<T: Pointee + ?Sized>(value: &T) {
337 let ptr = value as *const T;
338 let (raw, meta) = PtrExt::to_raw_parts(ptr);
339 let re_ptr = from_raw_parts::<T>(raw, meta);
340 assert_eq!(ptr, re_ptr);
341 }
342
343 #[test]
344 fn sized_types() {
345 test_pointee(&());
346 test_pointee(&42);
347 test_pointee(&true);
348 test_pointee(&[1, 2, 3, 4]);
349
350 struct TestUnit;
351
352 test_pointee(&TestUnit);
353
354 #[allow(dead_code)]
355 struct TestStruct {
356 a: (),
357 b: i32,
358 c: bool,
359 }
360
361 test_pointee(&TestStruct { a: (), b: 42, c: true });
362
363 struct TestTuple((), i32, bool);
364
365 test_pointee(&TestTuple((), 42, true));
366
367 struct TestGeneric<T>(T);
368
369 test_pointee(&TestGeneric(42));
370 }
371
372 #[test]
373 fn unsized_types() {
374 test_pointee("hello world");
375 test_pointee(&[1, 2, 3, 4] as &[i32]);
376 }
377
378 #[test]
379 fn trait_objects() {
380 #[pointee]
381 trait TestTrait {
382 fn foo(&self);
383 }
384
385 struct A;
386
387 impl TestTrait for A {
388 fn foo(&self) {}
389 }
390
391 let trait_object = &A as &dyn TestTrait;
392
393 test_pointee(trait_object);
394
395 let (_, meta) = PtrExt::to_raw_parts(trait_object as *const dyn TestTrait);
396
397 assert_eq!(meta.size_of(), 0);
398 assert_eq!(meta.align_of(), 1);
399
400 struct B(i32);
401
402 impl TestTrait for B {
403 fn foo(&self) {}
404 }
405
406 let b = B(42);
407 let trait_object = &b as &dyn TestTrait;
408
409 test_pointee(trait_object);
410
411 let (_, meta) = PtrExt::to_raw_parts(trait_object as *const dyn TestTrait);
412
413 assert_eq!(meta.size_of(), 4);
414 assert_eq!(meta.align_of(), 4);
415 }
416
417 #[test]
418 fn last_field_dst() {
419 #[allow(dead_code)]
420 #[derive(Pointee)]
421 struct Test<H, T> {
422 head: H,
423 tail: [T],
424 }
425
426 #[allow(dead_code)]
427 #[derive(Pointee)]
428 struct TestDyn {
429 tail: dyn core::any::Any,
430 }
431
432 #[pointee]
433 trait TestTrait {}
434
435 #[allow(dead_code)]
436 #[derive(Pointee)]
437 struct TestCustomDyn {
438 tail: dyn TestTrait,
439 }
440 }
441}