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> {}