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}