//! [![Crates.io](https://img.shields.io/crates/v/tagged-box?style=flat)](https://crates.io/crates/tagged-box)
//! [![Docs.rs](https://docs.rs/tagged-box/badge.svg)](https://docs.rs/tagged-box)
//! [![GitHub](https://img.shields.io/github/languages/top/Kixiron/tagged-box)](https://github.com/Kixiron/tagged-box)
//! [![LOC](https://tokei.rs/b1/github/Kixiron/tagged-box)](https://github.com/Kixiron/tagged-box)
//!
//! A `no_std`, zero-dependency crate for the creation and management of NaN-boxed types with
//! [`Box`]-like semantics and tagged pointers, tagged pointers and a macro interface to safely
//! create NaN-boxed enums.
//!
//! ## Quickstart
//!
//! First, add the crate to your `Cargo.lock` (Note: for variable reserved widths, see the [features] section)
//!
//! ```toml
//! tagged_box = "0.1.0"
//! ```
//!
//! The recommend way to use this crate is through the [`tagged_box!`] macro, as it's a safe
//! interface for using NaN-boxed enums.
//!
//! Next, for using the [`tagged_box!`] macro, add the following to the top of your file
//!
//! ```rust
//! use tagged_box::{tagged_box, TaggableContainer, TaggableInner};
//! ```
//!
//! Then you can use the macro as follows
//!
//! ```rust
//! # extern crate alloc;
//! # use alloc::string::String;
//! # use tagged_box::{tagged_box, TaggableContainer};
//! tagged_box! {
//! #[derive(Debug, Clone, PartialEq)]
//! struct Container, enum Item {
//! Integer(i32),
//! Boolean(bool),
//! String(String),
//! }
//! }
//!
//! let container = Container::from(String::from("Hello from tagged-box!"));
//!
//! assert_eq!(
//! container.into_inner(),
//! Item::String(String::from("Hello from tagged-box!"))
//! );
//! ```
//!
//! For working with NaN-boxes or [`TaggedBox`]es, simply add
//!
//! ```rust
//! use tagged_box::TaggedBox;
//! ```
//!
//! And for [`TaggedPointer`]s use
//!
//! ```rust
//! use tagged_box::TaggedPointer;
//! ```
//!
//! ## What this crate does
//!
//! This crate implements [NaN-Boxing] and [Tagged Pointers], which are a way to store extra data in the [unused bits of pointers].
//! While the two differ in implementation, they are semantically the same. In this crate, the [`TaggedBox`] type allows you to store
//! anywhere from 7 to 16 bits of arbitrary data in your pointer, depending on the [features] enabled. For explanation's sake,
//! I'll be using the `48bits` feature to explain, as it's the default and leads to the cleanest examples.
//! The pointers this applies to are 64 bits long, looking something like this
//!
//! ```text
//! 0000 0000 0000 0000
//! ```
//!
//! However, not all of these bits are used for the actual addressing of memory, so most pointers look like this
//!
//! ```text
//! 0000 FFFF FFFF FFFF
//! ^^^^
//! Free Data!
//! ```
//!
//! Those first 16 bits are free data, just begging to be used, and that's what [`TaggedPointer`] does. `TaggedPointer` simply
//! manages the pointer and the data (referred to as a 'discriminant' throughout this crate), making sure you get a pointer when you
//! need it and data when you need it, and not mixing those two up.
//!
//! [`TaggedBox`] goes one layer higher, storing an [enum discriminant] (Indicated by the type parameter) and directly storing the enum
//! variant's inner value to the heap. In short, `TaggedBox` is like a `Box` and an enum rolled into one.
//!
//! Ramping the abstraction up one more notch, we have the [`tagged_box!`] macro, which creates a container-type struct and an
//! associated `TaggedBox`-backed enum that can be seamlessly transferred between.
//!
//! ## Cargo Features
//!
//! This crate has a few features that change the number of free and reserved bits:
//!
//! - `48bits` (On by default): 48 bits of reserved pointer, 16 bits for data
//! - `49bits`: 49 bits of reserved pointer, 15 bits for data
//! - `50bits`: 50 bits of reserved pointer, 14 bits for data
//! - `51bits`: 51 bits of reserved pointer, 13 bits for data
//! - `52bits`: 52 bits of reserved pointer, 12 bits for data
//! - `53bits`: 53 bits of reserved pointer, 11 bits for data
//! - `54bits`: 54 bits of reserved pointer, 10 bits for data
//! - `55bits`: 55 bits of reserved pointer, 9 bits for data
//! - `56bits`: 56 bits of reserved pointer, 8 bits for data
//! - `57bits`: 57 bits of reserved pointer, 7 bits for data
//!
//! However, only one of these may be active at a time, otherwise a `compile_error` will be emitted.
//!
//! To select a feature, put the following in your `Cargo.toml`
//!
//! ```toml
//! [dependencies.tagged_box]
//! version = "0.1.0"
//! default-features = false
//! features = ["50bits"] # Select your feature here
//! ```
//!
//! [`Box`]: (https://doc.rust-lang.org/std/boxed/struct.Box.html)
//! [features]: #cargo-features
//! [NaN-Boxing]: https://wingolog.org/archives/2011/05/18/value-representation-in-javascript-implementations
//! [Tagged Pointers]: https://en.wikipedia.org/wiki/Tagged_pointer
//! [unused bits of pointers]: https://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details
//! [enum discriminant]: https://doc.rust-lang.org/reference/items/enumerations.html
//! [`TaggedBox`]: crate::TaggedBox
//! [`TaggedPointer`]: crate::TaggedPointer
//! [`tagged_box!`]: macro.tagged_box.html
// `no_std` is supported, but the `alloc` crate is required, as
// tagged values are allocated to the heap.
extern crate alloc;
// TODO: Much of this crate can be `const fn` once certain features from #57563 come through
// Needed features from #57563:
// - Dereferencing raw pointers via #51911
// - Bounds via rust-lang/rfcs#2632
// - &mut T references and borrows via #57349
// - Control flow via #49146
// - Panics via #51999
//
// https://github.com/rust-lang/rust/issues/57563
//
// TODO: Figure out how to allow `?Sized` within `TaggedBox` and `TaggedPointer` to allow for
// parity with `Box`
// 32bit arches use all 32 bits of their pointers, so an extra 16bit tag will have to be added.
// Any benefit from tagging is kinda lost, but it's worth it to allow compatibility for this crate
// between 32bit and 64bit arches.
//
//
// Possible `TaggedPointer` structure on 32bit arches:
// ```rust
// pub struct TaggedPointer {
// ptr: usize,
// tag: u8,
// }
// ```
//
// Note: Tagging of the lower bits is also possible due to alignment, but that only allows for 8 variants at best.
// this is better than nothing though, and should be implemented
compile_error!;
// Only pointer widths of 64bits and 32bits will be supported, unless 128bits ever becomes mainstream,
// but we'll cross that bridge when we get to it.
compile_error!;
/// Macro to create a compile error if none or more than one feature are enabled
generate_compile_error!
/// Implement various formatting traits on included structs
}
)+
};
}
pub use crate TaggedBox;
pub use Discriminant;
pub use ;
pub use TaggedPointer;