enum_ptr/base/
compact.rs

1use core::mem::{transmute_copy, ManuallyDrop};
2
3use crate::{CompactBorrow, CompactBorrowMut, CompactInnerCopy, Compactable};
4
5/// Compact representation of `T`. Only one-pointer wide.
6///
7/// It behaves like `T` for `Drop`, `Clone`, `Hash`, `Eq`, `Ord`, ...
8#[repr(transparent)]
9pub struct Compact<T: Compactable> {
10    pub(crate) inner: T::Inner,
11}
12
13impl<T: Compactable> Compact<T> {
14    /// Returns the underlying raw data.
15    #[inline]
16    pub fn as_raw_data(&self) -> *const u8 {
17        unsafe { transmute_copy(self) }
18    }
19
20    /// Returns the original value.
21    #[inline]
22    pub fn extract(self) -> T {
23        T::extract(self)
24    }
25
26    #[inline]
27    unsafe fn temp_extract(&self) -> ManuallyDrop<T> {
28        ManuallyDrop::new(T::extract(transmute_copy(self)))
29    }
30
31    /// Maps a `&T` to `U` by applying a function to a temporarily created
32    /// `T` value.
33    ///
34    /// Since the value is temporary, you cannot take references to it out
35    /// from this function.
36    ///
37    /// # Examples
38    ///
39    /// ```
40    /// # #[cfg(feature = "alloc")] {
41    /// use enum_ptr::{Compact, EnumPtr};
42    ///
43    /// #[derive(EnumPtr, Debug)]
44    /// #[repr(C, usize)]
45    /// enum Foo {
46    ///     A(Box<i32>),
47    ///     B(Box<u32>),
48    /// }
49    ///
50    /// let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
51    /// let result = foo.map_ref(|f| match f {
52    ///     Foo::A(r) => **r,
53    ///     _ => unreachable!(),
54    /// });
55    /// assert_eq!(result, 1);
56    /// # }
57    /// ```
58    #[inline]
59    pub fn map_ref<U>(&self, f: impl FnOnce(&T) -> U) -> U {
60        unsafe { f(&self.temp_extract()) }
61    }
62
63    /// Maps a `&mut T` to `U` by applying a function to a temporarily created
64    /// `T` value.
65    ///
66    /// Since the value is temporary, you cannot take references to it out
67    /// from this function.
68    ///
69    /// # Safety
70    ///
71    /// See issue [#3](https://github.com/QuarticCat/enum-ptr/issues/3).
72    ///
73    /// # Examples
74    ///
75    /// ```
76    /// # #[cfg(feature = "alloc")] {
77    /// use enum_ptr::{Compact, EnumPtr};
78    ///
79    /// #[derive(EnumPtr, Debug, PartialEq, Eq)]
80    /// #[repr(C, usize)]
81    /// enum Foo {
82    ///     A(Box<i32>),
83    ///     B(Box<u32>),
84    /// }
85    ///
86    /// let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
87    /// unsafe {
88    ///     foo.map_mut(|f| match f {
89    ///         Foo::A(r) => **r = 2,
90    ///         _ => unreachable!(),
91    ///     });
92    /// }
93    /// assert_eq!(foo.extract(), Foo::A(Box::new(2)));
94    /// # }
95    /// ```
96    #[inline]
97    pub unsafe fn map_mut<U>(&mut self, f: impl FnOnce(&mut T) -> U) -> U {
98        f(&mut self.temp_extract())
99    }
100
101    // /// Replaces the wrapped value with a new one computed from f, returning
102    // /// the old value, without deinitializing either one.
103    // ///
104    // /// # Examples
105    // ///
106    // /// ```
107    // /// # #[cfg(feature = "alloc")] {
108    // /// use enum_ptr::{Compact, EnumPtr};
109    // ///
110    // /// #[derive(EnumPtr, Debug, PartialEq, Eq)]
111    // /// #[repr(C, usize)]
112    // /// enum Foo {
113    // ///     A(Box<i32>),
114    // ///     B(Box<u32>),
115    // /// }
116    // ///
117    // /// let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
118    // /// let old = foo.replace_with(|_| Foo::B(Box::new(2)));
119    // /// assert_eq!(old, Foo::A(Box::new(1)));
120    // /// assert_eq!(foo.extract(), Foo::B(Box::new(2)));
121    // /// # }
122    // /// ```
123    // #[inline]
124    // pub fn replace_with(&mut self, f: impl FnOnce(&mut T) -> T) -> T {
125    //     let mut old = T::from(Self { ..*self });
126    //     let new = f(&mut old);
127    //     self.data = unsafe { crate::compact(new) };
128    //     old
129    // }
130}
131
132impl<T: CompactBorrow> Compact<T> {
133    /// Returns a reference type that acts like `&T`.
134    ///
135    /// Check [`EnumPtr`](crate::EnumPtr) for more details.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// # #[cfg(feature = "alloc")] {
141    /// use enum_ptr::{Compact, EnumPtr};
142    ///
143    /// #[derive(EnumPtr, Debug)]
144    /// #[enum_ptr(borrow)] // required
145    /// #[repr(C, usize)]
146    /// enum Foo {               // enum FooRef<'enum_ptr> {
147    ///     A(Box<i32>),         //     A(&'enum_ptr i32),
148    ///     B(Option<Box<u32>>), //     B(Option<&'enum_ptr u32>),
149    /// }                        // }
150    ///
151    /// let foo: Compact<_> = Foo::A(Box::new(1)).into();
152    /// match foo.borrow() {
153    ///     FooRef::A(inner) => assert_eq!(inner, &1),
154    ///     _ => unreachable!(),
155    /// }
156    /// # }
157    /// ```
158    #[inline]
159    pub fn borrow(&self) -> <T as CompactBorrow>::Target<'_> {
160        T::borrow(self)
161    }
162}
163
164impl<T: CompactBorrowMut> Compact<T> {
165    /// Returns a reference type that acts like `&mut T`.
166    ///
167    /// Check [`EnumPtr`](crate::EnumPtr) for more details.
168    ///
169    /// # Examples
170    ///
171    /// ```
172    /// # #[cfg(feature = "alloc")] {
173    /// use enum_ptr::{Compact, EnumPtr};
174    ///
175    /// #[derive(EnumPtr, Debug)]
176    /// #[enum_ptr(borrow_mut)] // required
177    /// #[repr(C, usize)]
178    /// enum Foo {               // enum FooRefMut<'enum_ptr> {
179    ///     A(Box<i32>),         //     A(&'enum_ptr mut i32),
180    ///     B(Option<Box<u32>>), //     B(Option<&'enum_ptr mut u32>),
181    /// }                        // }
182    ///
183    /// let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
184    /// match foo.borrow_mut() {
185    ///     FooRefMut::A(inner) => assert_eq!(inner, &mut 1),
186    ///     _ => unreachable!(),
187    /// }
188    /// # }
189    /// ```
190    #[inline]
191    pub fn borrow_mut(&mut self) -> <T as CompactBorrowMut>::Target<'_> {
192        T::borrow_mut(self)
193    }
194}
195
196impl<T: Compactable> Clone for Compact<T>
197where
198    T::Inner: Clone,
199{
200    #[inline]
201    fn clone(&self) -> Self {
202        let inner = self.inner.clone();
203        Self { inner }
204    }
205}
206
207impl<T: Compactable<Inner = CompactInnerCopy<T>> + Copy> Copy for Compact<T> {}
208
209impl<T: Compactable + PartialEq> PartialEq for Compact<T> {
210    #[inline]
211    fn eq(&self, other: &Self) -> bool {
212        self.map_ref(|this| other.map_ref(|that| this.eq(that)))
213    }
214}
215
216impl<T: Compactable + Eq> Eq for Compact<T> {}
217
218impl<T: Compactable + PartialOrd> PartialOrd for Compact<T> {
219    #[inline]
220    fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
221        self.map_ref(|this| other.map_ref(|that| this.partial_cmp(that)))
222    }
223}
224
225impl<T: Compactable + Ord> Ord for Compact<T> {
226    #[inline]
227    fn cmp(&self, other: &Self) -> core::cmp::Ordering {
228        self.map_ref(|this| other.map_ref(|that| this.cmp(that)))
229    }
230}
231
232impl<T: Compactable + core::fmt::Debug> core::fmt::Debug for Compact<T> {
233    #[inline]
234    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
235        self.map_ref(|this| this.fmt(f))
236    }
237}
238
239impl<T: Compactable + Default> Default for Compact<T> {
240    fn default() -> Self {
241        T::default().compact()
242    }
243}
244
245impl<T: Compactable + core::hash::Hash> core::hash::Hash for Compact<T> {
246    #[inline]
247    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
248        self.map_ref(|this| this.hash(state))
249    }
250}
251
252unsafe impl<T: Compactable + Send> Send for Compact<T> {}
253
254unsafe impl<T: Compactable + Sync> Sync for Compact<T> {}