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
//! # 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 APIs with different flavors.
//!
//! ## Flavor 1: `CompactCopy`
//!
//! If your enum type is [`Copy`] (e.g., consists of only `&T`s), you can
//! convert it to [`CompactCopy`]. Each time you need to use it, just copy
//! and [`extract`](CompactCopy::extract) it. Easy-peasy!
//!
//! Sadly, due to language limitations, we cannot combine [`Compact`] and
//! [`CompactCopy`] into one type.
//!
//! ## 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>`. Check
//! [`FieldDeref`] and [`FieldDerefMut`] for more 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`.
//!
//! ## Flavor 4: `map_ref` & `map_mut` *(legacy)*
//!
//! [`map_ref`](Compact::map_ref) and [`map_mut`](Compact::map_mut) will create
//! temporary objects that drop as soon as your closure ends. They can
//! sometimes be useful if you don't want to derive reference objects.
//!
//! ## Extension
//!
//! All important traits are public. You can implement them for your own types.
//!
//! # 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 either trigger a compilation error or
//! a run-time panic. Passed assertions will be optimized out. That is to say,
//! rule checks won't affect the run-time performance.
//!
//! [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
#![no_std]
#[cfg(feature = "alloc")]
extern crate alloc;
mod compact;
mod compact_copy;
mod convert;
mod traits;
mod utils;
pub use compact::*;
pub use compact_copy::*;
pub use convert::*;
pub use traits::*;
pub use utils::*;
/// 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 enum_ptr_derive::EnumPtr;