devela/sys/mem/ptr/fat.rs
1// devela::sys::mem::ptr::fat
2//
3//! Fat pointers.
4//
5// https://github.com/storycraft/unsized-stack
6// Vendored from [unsized-stack](https://crates.io/crates/unsized-stack/0.2.0)
7//
8// MODIFICATIONS:
9// - refactored, documented, namespaced.
10
11// WAIT: [ptr_metadata](https://github.com/rust-lang/rust/issues/81513)
12// use core::ptr::{metadata, from_raw_parts};
13
14/// Represents a fat pointer with separate data and metadata pointers.
15///
16#[doc = crate::doc_!(vendor: "unsized-stack")]
17#[derive(Debug, Clone, Copy)]
18#[repr(C)]
19pub struct FatPtr {
20 ptr: *const (),
21 metadata: *const (),
22}
23
24impl FatPtr {
25 /// Creates a new `FatPtr` from a data pointer and metadata.
26 pub const fn new<T>(ptr: *const T, metadata: *const ()) -> Self {
27 Self { ptr: ptr as _, metadata }
28 }
29
30 /// Returns the raw pointer part of the fat pointer.
31 pub const fn ptr(&self) -> *const () {
32 self.ptr
33 }
34
35 /// Returns the metadata part of the fat pointer.
36 pub const fn metadata(&self) -> *const () {
37 self.metadata
38 }
39
40 /* */
41
42 /// Checks if a type `T` is a valid dynamically sized type (DST).
43 // MAYBE make private
44 pub const fn check_valid<T: ?Sized>() {
45 if size_of::<*const T>() != size_of::<FatPtr>() {
46 panic!("Type is not valid DST");
47 }
48 }
49
50 /// Composes a fat pointer `*const T` from a `FatPtr` structure.
51 pub const fn to_raw_ptr<T: ?Sized>(fat_ptr: FatPtr) -> *const T {
52 Self::check_valid::<T>();
53
54 // SAFETY: relying on unspecified fat pointer representation
55 unsafe { FatPtrRepr { fat_ptr }.ptr_const }
56 }
57 /// Decomposes a fat pointer `*const T` into a `FatPtr` structure.
58 pub const fn from_raw_ptr<T: ?Sized>(fat_ptr: *const T) -> FatPtr {
59 Self::check_valid::<T>();
60
61 // SAFETY: relying on unspecified fat pointer representation
62 unsafe { FatPtrRepr { ptr_const: fat_ptr }.fat_ptr }
63 }
64
65 // WAIT: [ptr_metadata](https://github.com/rust-lang/rust/issues/81513)
66 // /// Composes a fat pointer `*const T` from a `FatPtr` using stable APIs.
67 // pub const fn compose2<T: ?Sized>(fat_ptr: FatPtr) -> *const T {
68 // unsafe { from_raw_parts(fat_ptr.ptr, fat_ptr.metadata as _) }
69 // }
70 // /// Decomposes a fat pointer `*const T` into a `FatPtr` using stable APIs.
71 // pub const fn decompose2<T: ?Sized>(ptr: *const T) -> FatPtr {
72 // FatPtr {
73 // ptr: ptr as *const (),
74 // metadata: metadata(ptr) as *const (),
75 // }
76 // }
77}
78
79/// A union that represents either a raw or fat pointer.
80#[repr(C)]
81union FatPtrRepr<T: ?Sized> {
82 pub ptr_const: *const T,
83 pub fat_ptr: FatPtr,
84}
85
86#[cfg(test)]
87mod tests {
88 use super::FatPtr;
89
90 #[test]
91 fn from_raw_ptr() {
92 let slice: &[usize] = &[0_usize];
93 let fat_ptr = FatPtr::from_raw_ptr(slice as *const [usize]);
94 assert_eq!(fat_ptr.metadata(), 1 as *const ());
95 }
96}