1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
//! This crate provides a custom derive macro [`EnumPtr`] to generate bridges
//! between an enum `T` and [`Compact<T>`] with minimum cost. [`Compact<T>`] is
//! the compact representation of `T`, and it is only one pointer wide.
//!
//! This is viable because some types' low bits are always zeros.
//! [`Compact<T>`] utilizes these bits to store the tag (discriminant).
//!
//! # Examples
//!
//! ```
//! use enum_ptr::{Aligned, Compact, EnumPtr, ShiftUsize, Unit};
//!
//! # #[derive(Debug, PartialEq, Eq, Clone)]
//! #[derive(EnumPtr)]
//! #[repr(C, usize)] // required
//! enum Foo<'a, T: Aligned> {
//! A(T), // supports any `T: Aligned`
//! B(&'a u64),
//! C(Unit), // use `Unit` for unit variants
//! D(ShiftUsize<3>), // you can even use non-pointers
//! # #[cfg(feature = "alloc")]
//! E(Box<i64>),
//! }
//!
//! let compact_foo: Compact<_> = Foo::A(&1u64).into();
//! let original_foo: Foo<_> = compact_foo.into();
//! #
//! # let test = |f: Foo<&u64>| assert_eq!(f.clone(), Foo::from(Compact::from(f)));
//! # test(Foo::A(&0));
//! # test(Foo::B(&1));
//! # test(Foo::C(Unit::new()));
//! # test(Foo::D(ShiftUsize::new(2)));
//! # #[cfg(feature = "alloc")]
//! # test(Foo::E(Box::new(3)));
//! ```
//!
//! # Usage
//!
//! This crate provides multiple flavors of APIs.
//!
//! ## Flavor 1: copy everywhere
//!
//! If your enum type is [`Copy`] (e.g., consists of only `&T`s), you can
//! mark it with `#[enum_ptr(copy)]`. Each time you need to use it, just copy
//! and [`extract`](Compact::extract) it. Easy-peasy!
//!
//! Due to language limitations, we cannot automatically infer `copy`.
//!
//! <details>
//! <summary>Click to show examples</summary>
//!
//! ```
//! use enum_ptr::{Compact, EnumPtr};
//!
//! #[derive(EnumPtr, Debug, Clone, Copy, PartialEq, Eq)]
//! #[enum_ptr(copy)] // required
//! #[repr(C, usize)]
//! enum Foo<'a, 'b> {
//! A(&'a i32),
//! B(&'b u32),
//! }
//!
//! let foo: Compact<_> = Foo::A(&1).into();
//! assert_eq!(foo.extract(), Foo::A(&1));
//! assert_ne!(foo.extract(), Foo::B(&2));
//! ```
//! </details>
//!
//! ## Flavor 2: `get_ref` & `get_mut`
//!
//! If your enum type is not [`Copy`], and you happens to only have references
//! to the compact value, you can use [`get_ref`] and [`get_mut`] to get
//! references to **the object that it points to**.
//!
//! For example, if you hold a compact `Box<T>`, you can use these APIs to
//! access `&T` and `&mut T`. Since there's no `Box<T>` in the memory (but only
//! its compact form), we cannot create `&Box<T>` and `&mut Box<T>`. The target
//! types are specified by [`FieldDeref`] and [`FieldDerefMut`].
//!
//! <details>
//! <summary>Click to show examples</summary>
//!
//! ```
//! # #[cfg(feature = "alloc")] {
//! use enum_ptr::{get_mut, get_ref, Compact, EnumPtr};
//!
//! #[derive(EnumPtr)]
//! #[repr(C, usize)]
//! enum Foo {
//! A(Box<i32>),
//! B(Box<u32>),
//! }
//!
//! let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
//! assert_eq!(get_ref!(foo, Foo::A), Some(&1));
//! assert_eq!(get_mut!(foo, Foo::A), Some(&mut 1));
//! # }
//! ```
//! </details>
//!
//! ## Flavor 3: `borrow` & `borrow_mut`
//!
//! [`get_ref`] and [`get_mut`] can be troublesome if you want to deal with
//! multiple variants at together. In that case, you can use
//! [`borrow`](Compact::borrow) and [`borrow_mut`](Compact::borrow_mut). They
//! will return derived reference types that you can `match`.
//!
//! Check the documentation of [`EnumPtr`] for more details.
//!
//! <details>
//! <summary>Click to show examples</summary>
//!
//! ```
//! # #[cfg(feature = "alloc")] {
//! use enum_ptr::{Compact, EnumPtr};
//!
//! #[derive(EnumPtr, Debug)]
//! #[enum_ptr(borrow, borrow_mut)] // required
//! #[repr(C, usize)]
//! enum Foo {
//! A(Box<i32>),
//! B(Option<Box<u32>>),
//! }
//!
//! // enum FooRef<'enum_ptr> {
//! // A(&'enum_ptr i32),
//! // B(Option<&'enum_ptr u32>),
//! // }
//!
//! // enum FooRefMut<'enum_ptr> {
//! // A(&'enum_ptr mut i32),
//! // B(Option<&'enum_ptr mut u32>),
//! // }
//!
//! let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
//! match foo.borrow() {
//! FooRef::A(inner) => assert_eq!(inner, &1),
//! _ => unreachable!(),
//! }
//! match foo.borrow_mut() {
//! FooRefMut::A(inner) => assert_eq!(inner, &mut 1),
//! _ => unreachable!(),
//! }
//! # }
//! ```
//! </details>
//!
//! ## Flavor 4: `map_ref` & `map_mut` *(legacy)*
//!
//! [`map_ref`](Compact::map_ref) and [`map_mut`](Compact::map_mut) will copy
//! (= [`core::mem::transmute_copy`]) temporary objects out of its compact ones,
//! that [`core::mem::forget`]-ed as soon as your closure ends, so that no
//! destructor is needed to be run. They are important for internal
//! implementations, but less useful for lib users.
//!
//! <details>
//! <summary>Click to show examples</summary>
//!
//! ```
//! # #[cfg(feature = "alloc")] {
//! use enum_ptr::{Compact, EnumPtr};
//!
//! #[derive(EnumPtr, Debug, PartialEq, Eq)]
//! #[repr(C, usize)]
//! enum Foo {
//! A(Box<i32>),
//! B(Box<u32>),
//! }
//!
//! let mut foo: Compact<_> = Foo::A(Box::new(1)).into();
//!
//! let result = foo.map_ref(|f| match f {
//! Foo::A(r) => **r,
//! _ => unreachable!(),
//! });
//! assert_eq!(result, 1);
//!
//! unsafe {
//! foo.map_mut(|f| match f {
//! Foo::A(r) => **r = 2,
//! _ => unreachable!(),
//! });
//! }
//! assert_eq!(foo.extract(), Foo::A(Box::new(2)));
//! # }
//! ```
//! </details>
//!
//! ## Extension
//!
//! Most of the important traits are public. You can implement them for your
//! own types.
//!
//! - To make your types available in [`EnumPtr`], implement [`Aligned`].
//! - To make your types available in [`get_ref`] / [`get_mut`] and
//! `#[enum_ptr(borrow)]` / `#[enum_ptr(borrow_mut)]`, implement
//! [`FieldDeref`] / [`FieldDerefMut`].
//! - Unsatisfied with derived reference types? Implement [`CompactBorrow`] /
//! [`CompactBorrowMut`] by hand.
//!
//! # Limitations
//!
//! Suppose we are deriving from `Foo`, then
//!
//! - **`Foo` must have a `#[repr(C, usize)]`.**
//! - According to the [RFC] and the [Rust Reference], `#[repr(C, usize)]`
//! guarantees the memory layout and discriminant values. Thus, we can
//! safely transmute between two representations.
//! - **Each variant of `Foo` must have exactly one field.**
//! - Unit variants are not allowed due to performance concerns.
//! - If you need a unit variant, use [`Unit`].
//! - **Each variant of `Foo` must have enough alignment to store the tag.**
//! - Currently this crate cannot utilize high bits.
//!
//! Any violation of these rules will trigger a **compilation error**.
//!
//! [RFC]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
//! [Rust Reference]: https://doc.rust-lang.org/reference/items/enumerations.html#custom-discriminant-values-for-fieldless-enumerations
//!
//! # Features
//!
//! - `alloc` *(default)* --- `Box`, `Rc` and `Arc` support
extern crate alloc;
pub use *;
pub use *;
pub use *;
/// Derives conversions to and from [`Compact`].
///
/// # Examples
///
/// ```
/// # #[cfg(feature = "alloc")] {
/// use enum_ptr::{EnumPtr, Unit};
///
/// #[derive(EnumPtr)]
/// #[enum_ptr(
/// // copy, // derives conversions to and from `CompactCopy`
/// borrow( // derives a reference type and `impl CompactBorrow`
/// name = "FooRef", // default: ident + "Ref"
/// derive(Clone, Copy), // default: none
/// ),
/// borrow_mut( // derives a reference type and `impl CompactBorrowMut`
/// name = "FooRefMut", // default: ident + "RefMut"
/// derive(Debug), // default: none
/// ),
/// )]
/// #[repr(C, usize)]
/// enum Foo {
/// // `borrow` / `borrow_mut` requires all unskipped fields
/// // to implement `FieldDeref` / `FieldDerefMut`
/// A(Box<i64>), // ref type: `&i64` / `&mut i64`
/// B(Option<Box<i64>>), // ref type: `Option<&i64>` / `Option<&mut i64>`
///
/// // use `skip` to skip both, or use `skip_borrow` / `skip_borrow_mut`
/// #[enum_ptr(skip)]
/// C(Unit), // ref type: `PhantomData` (skipped)
/// }
/// # }
/// ```
pub use EnumPtr;