musli_zerocopy/pointer/
pointee.rs

1use core::alloc::{Layout, LayoutError};
2use core::mem::size_of;
3
4use crate::error::CoerceError;
5use crate::pointer::Size;
6use crate::traits::ZeroCopy;
7
8mod sealed {
9    use crate::mem::MaybeUninit;
10    use crate::pointer::Pointee;
11    use crate::traits::ZeroCopy;
12
13    pub trait Sealed {}
14
15    impl<T> Sealed for MaybeUninit<T> where T: Pointee {}
16    impl<T> Sealed for T where T: ZeroCopy {}
17    impl<T> Sealed for [T] where T: ZeroCopy {}
18    impl Sealed for str {}
19}
20
21/// The trait for a value that can be pointed to by a [`Ref<T>`].
22///
23/// This ultimately determines the layout of [`Ref<T>`] as for unsized types it
24/// needs to accommodate the size of the pointed-to type as well.
25///
26/// ```
27/// use std::mem::size_of;
28///
29/// use musli_zerocopy::Ref;
30///
31/// assert_eq!(size_of::<Ref::<u32>>(), 4);
32/// assert_eq!(size_of::<Ref::<[u32]>>(), 8);
33/// ```
34///
35/// [`Ref<T>`]: crate::Ref
36pub trait Pointee: self::sealed::Sealed {
37    /// Metadata associated with a pointee.
38    type Metadata: Copy;
39
40    /// The stored representation of the pointee metadata.
41    #[doc(hidden)]
42    type Stored<O>: Copy + ZeroCopy
43    where
44        O: Size;
45
46    /// Try to construct packed value from its metadata.
47    #[doc(hidden)]
48    fn try_from_metadata<O>(metadata: Self::Metadata) -> Result<Self::Stored<O>, CoerceError>
49    where
50        O: Size;
51
52    /// The size of `T` with the given stored metadata.
53    #[doc(hidden)]
54    fn size<O>(metadata: Self::Stored<O>) -> Option<usize>
55    where
56        O: Size;
57
58    /// The alignment of `T` with the given stored metadata.
59    #[doc(hidden)]
60    fn align<O>(metadata: Self::Stored<O>) -> usize
61    where
62        O: Size;
63
64    /// The layout of `T` with the given stored metadata.
65    #[doc(hidden)]
66    fn pointee_layout<O>(metadata: Self::Stored<O>) -> Result<Layout, LayoutError>
67    where
68        O: Size;
69}
70
71impl<T> Pointee for T
72where
73    T: ZeroCopy,
74{
75    type Metadata = ();
76    type Stored<O>
77        = ()
78    where
79        O: Size;
80
81    #[inline(always)]
82    fn try_from_metadata<O>((): ()) -> Result<Self::Stored<O>, CoerceError>
83    where
84        O: Size,
85    {
86        Ok(())
87    }
88
89    #[inline(always)]
90    fn size<O>((): Self::Stored<O>) -> Option<usize>
91    where
92        O: Size,
93    {
94        Some(size_of::<T>())
95    }
96
97    #[inline(always)]
98    fn align<O>((): Self::Stored<O>) -> usize
99    where
100        O: Size,
101    {
102        align_of::<T>()
103    }
104
105    #[inline(always)]
106    fn pointee_layout<O>((): Self::Stored<O>) -> Result<Layout, LayoutError>
107    where
108        O: Size,
109    {
110        Ok(Layout::new::<T>())
111    }
112}
113
114impl<T> Pointee for [T]
115where
116    T: ZeroCopy,
117{
118    type Metadata = usize;
119    type Stored<O>
120        = O
121    where
122        O: Size;
123
124    #[inline(always)]
125    fn try_from_metadata<O>(metadata: usize) -> Result<O, CoerceError>
126    where
127        O: Size,
128    {
129        O::try_from_usize(metadata)
130    }
131
132    #[inline(always)]
133    fn size<O>(metadata: Self::Stored<O>) -> Option<usize>
134    where
135        O: Size,
136    {
137        let len = metadata.as_usize();
138        size_of::<T>().checked_mul(len)
139    }
140
141    #[inline(always)]
142    fn align<O>(_: Self::Stored<O>) -> usize
143    where
144        O: Size,
145    {
146        align_of::<T>()
147    }
148
149    #[inline(always)]
150    fn pointee_layout<O>(metadata: Self::Stored<O>) -> Result<Layout, LayoutError>
151    where
152        O: Size,
153    {
154        let len = metadata.as_usize();
155        Layout::array::<T>(len)
156    }
157}
158
159impl Pointee for str {
160    type Metadata = usize;
161    type Stored<O>
162        = O
163    where
164        O: Size;
165
166    #[inline(always)]
167    fn try_from_metadata<O>(metadata: usize) -> Result<O, CoerceError>
168    where
169        O: Size,
170    {
171        O::try_from_usize(metadata)
172    }
173
174    #[inline(always)]
175    fn size<O>(metadata: Self::Stored<O>) -> Option<usize>
176    where
177        O: Size,
178    {
179        Some(metadata.as_usize())
180    }
181
182    #[inline(always)]
183    fn align<O>(_: Self::Stored<O>) -> usize
184    where
185        O: Size,
186    {
187        align_of::<u8>()
188    }
189
190    #[inline(always)]
191    fn pointee_layout<O>(metadata: Self::Stored<O>) -> Result<Layout, LayoutError>
192    where
193        O: Size,
194    {
195        Layout::array::<u8>(metadata.as_usize())
196    }
197}