#![no_std]
//! This crate provides a procedural macro ([`Pack`](macro@Pack)) for deriving a
//! [bit field](https://en.wikipedia.org/wiki/Bit_field) from a Rust type.
//!
//! # Differentiation
//!
//! The driving motivation for this crate is lock-free programming,
//! which often requires packing data into a `u64` or `u128` so it
//! can be atomically updated. As a result, we don't support
//! parsing-related functionality, like checked construction of a packed
//! type from arbitrary bytes, packed types larger than 128 bits,
//! or non-native endianness. We also don't suport arrays or
//! anonymous tuples.
//!
//! This crate does provide the following features that were hard to
//! find in existing crates:
//!
//! - Composition of bit fields
//! - Generic bit fields
//! - Enums with struct and tuple variants
//! - `const` inherent methods and constructors (that work with generics, on stable Rust)
//! - Append-only: does not overwrite original type
//! - Nonzero support (e.g., can use [`NonZeroU64`] to enable niche optimizations)
//!
//! See also:
//! - [bitfield-struct-rs](https://github.com/wrenger/bitfield-struct-rs)
//! - [bilge](https://github.com/hecatia-elegua/bilge)
//! - [modular_bitfield](https://github.com/modular-bitfield/modular-bitfield)
//! - [bitbybit](https://github.com/danlehmann/bitfield)
//!
//! # Conditional compilation
//!
//! - The `atomic` feature enables support for atomic operations on packed types.
//! - The `u128` feature enables support for packed types up to 128 bits instead of 64 bits.
//! - The `atomic-u128` feature enables support for atomic operations on 128 bit packed types via
//!   the [`portable-atomic`](https://github.com/taiki-e/portable-atomic) crate.
//!
//! # Examples
//!
//! ```rust
//! # mod example {
//! use core::marker::PhantomData;
//! use ribbit::u12;
//! use ribbit::u52;
//! use ribbit::u31;
//!
//! // Enums with data
//! #[derive(ribbit::Pack, Copy, Clone, Debug, PartialEq, Eq)]
//! #[ribbit(size = 34, derive(Debug, Eq))]
//! pub enum Enum {
//!     Unit,
//!     #[ribbit(size = 16)]
//!     Tuple(u8, u8),
//!     #[ribbit(size = 32)]
//!     Struct {
//!         a: bool,
//!         b: u31,
//!     }
//! }
//!
//! // Generic types
//! #[derive(ribbit::Pack)]
//! #[ribbit(size = 64)]
//! pub struct Versioned<T, U> {
//!     // Configurable method generation
//!     #[ribbit(with(vis = "pub"))]
//!     version: u12,
//!     // Composition of bit fields
//!     #[ribbit(size = 52, get(vis = "pub"), with(skip))]
//!     data: T,
//!     _type: PhantomData<U>,
//! }
//!
//! impl<T: Copy, U> Clone for Versioned<T, U> {
//!     fn clone(&self) -> Self {
//!         *self
//!     }
//! }
//! impl<T: Copy, U> Copy for Versioned<T, U> {}
//!
//! // Non-zero support
//! use core::num::NonZeroU8;
//! use ribbit::u3;
//!
//! #[derive(ribbit::Pack, Copy, Clone)]
//! #[ribbit(size = 11, non_zero)]
//! struct NonZero(u3, NonZeroU8);
//!
//! const _: () = {
//!     assert!(
//!         core::mem::size_of::<ribbit::Packed<NonZero>>() ==
//!         core::mem::size_of::<Option<ribbit::Packed<NonZero>>>(),
//!     );
//!     assert!(
//!         core::mem::align_of::<ribbit::Packed<NonZero>>() ==
//!         core::mem::align_of::<Option<ribbit::Packed<NonZero>>>()
//!     );
//! };
//!
//! # }
//! # // HACK: needed to resolve module paths correctly
//! # // https://users.rust-lang.org/t/private-fields-in-macro-generated-structs/120052
//! # fn main() {
//! # pub use example::*;
//! # use ribbit::u12;
//! # use ribbit::u52;
//! # use ribbit::u31;
//! // Const operations on stable
//! let unit = const {
//!     ribbit::Packed::<Versioned<Enum, ()>>::new(u12::new(5), ribbit::Packed::<Enum>::new_unit())
//!         .with_version(u12::new(6))
//!         .data()
//! };
//!
//! use ribbit::Unpack as _;
//! assert_eq!(unit.unpack(), Enum::Unit);
//!
//! let tuple = const { ribbit::Packed::<Enum>::new_tuple(12, 15) };
//! assert_ne!(tuple.unpack(), Enum::Unit);
//!
//! // Atomic support
//! use core::sync::atomic::Ordering;
//! let atomic = ribbit::Atomic::<Enum>::new_packed(tuple);
//! // Operate on packed types
//! assert_eq!(
//!     atomic.compare_exchange_packed(unit, tuple, Ordering::Relaxed, Ordering::Relaxed),
//!     Err(tuple),
//! );
//! // Or on unpacked types
//! assert_eq!(
//!     atomic.compare_exchange(tuple.unpack(), unit.unpack(), Ordering::Relaxed, Ordering::Relaxed),
//!     Ok(tuple.unpack()),
//! );
//!
//! assert_eq!(
//!     atomic.load(Ordering::Relaxed),
//!     unit.unpack(),
//! );
//! # }
//! ```

/// Derive a packed representation of the (unpacked) input type.
///
/// The packed type is backed by a single raw type ([`Unpack::Raw`])
/// and `[repr(transparent)]`.
///
/// **Trait implementations**.
///
/// Some traits are implemented unconditionally---[`Pack`](trait@Pack) for the unpacked type,
/// and [`Unpack`][trait@Unpack], [`Copy`], and [`Clone`] for the packed type---while
/// other traits can optionally be derived for the packed type:
/// - [`From`]: generates bidirectional implementations between packed and unpacked types
/// - [`Debug`][core::fmt::Debug]: forwards to [`Debug`][core::fmt::Debug] on the unpacked type
/// - [`Hash`][core::hash::Hash], [`Ord`], and [`Eq`]: same as the standard derives,
///   but with no bounds on generic parameters
///   ([perfect derives](https://smallcultfollowing.com/babysteps//blog/2022/04/12/implied-bounds-and-perfect-derive/)).
///
/// **Method implementations**.
///
/// The following inherent methods on the packed type are `const` and implemented by default:
/// - `new`: Safe constructors (enum variants with name `v` have function `new_v`)
/// - `get`: Field getters (fields with name `n` have method `n`; fields with index `i` have method `_i`)
/// - `with`: Field updaters (immutable) (fields with name `n` have method `with_n`; fields with index `i` have method `with_i`)
/// - `into_raw`: Conversion to raw type
/// - `from_raw_unchecked`: Unsafe constructors from raw type (enum variants with name `v` have function `v_from_raw_unchecked`)
///
/// <div class = "warning">
///
/// **NOTE**: the packed type is generated inside a private module to prevent
/// tampering with its internal fields. We're mostly able to hide this implementation
/// detail, with two exceptions:
///
/// 1. Any field with a user-defined type needs to use an absolute path (e.g., `crate::Struct`),
///    so it resolves correctly from both the outer and inner modules.
///
/// 2. This derive cannot be used on types inside a function or an anonymous scope,
///    as the packed type must be able to resolve the unpacked type via `super`
///    (see also: [this bon blog post](https://bon-rs.com/blog/the-weird-of-function-local-types-in-rust)).
///
/// </div>
///
/// # Attributes
///
/// This derive macro is controlled by attributes under the `ribbit` namespace.
///
/// **Variant attributes**.
///
/// These can be used on top-level structs and enum variants.
///
/// ```rust
/// # mod variant_attributes {
/// use core::num::NonZeroU64;
///
/// #[derive(ribbit::Pack, Copy, Clone)]
/// #[ribbit(
///     // Indicate the size of this variant or struct in bits (validated at compile time).
///     // Note: this can be larger than the actual number of bits required,
///     // in which case the most significant unoccupied bits must be zero.
///     //
///     // Currently required for top-level items.
///     size = 64,
///     // Mark this type as non-zero (validated at compile time).
///     // A struct is non-zero if it contains a non-zero field.
///     // An enum is non-zero if either (a) all variant discriminant values are non-zero,
///     // or (b) the variant with a zero discriminant contains a non-zero field.
///     non_zero,
///     // Control generation of safe constructor function.
///     new(vis = "pub", rename = "new", skip = false),
///     // Control generation of unsafe constructor function.
///     from_raw_unchecked(vis = "", rename = "from_raw_unchecked", skip = false),
/// )]
/// pub struct Struct(NonZeroU64);
/// # }
/// ```
///
/// **Item attributes**.
///
/// These can be used on top-level structs and enums, in addition to all variant attributes above.
///
/// ```rust
/// # mod item_attributes {
/// #[derive(ribbit::Pack, Copy, Clone, Debug)]
/// #[ribbit(
///     // Just here to make example compile.
///     size = 0,
///     // Control visibility and naming of packed type.
///     packed(vis = "pub(self)", rename = "EnumPacked"),
///     // Control generation of packed to raw conversion method.
///     into_raw(vis = "pub(self)", rename = "into_raw", skip = false),
///     // Custom derives for the packed type.
///     derive(Debug, From, Hash, Ord, Eq),
///     // Forward arbitrary tokens as attributes on the packed type.
///     forward(doc = "Hello"),
/// )]
/// enum Enum {}
/// # }
/// ```
///
/// **Field attributes**.
///
/// These can be used on enum variant and struct fields.
///
/// ```
/// # mod field_attributes {
/// use core::num::NonZeroU8;
///
/// #[derive(ribbit::Pack, Copy, Clone)]
/// #[ribbit(size = 8, non_zero)]
/// struct Struct {
///     #[ribbit(
///         // Size of field in bits (required for user-defined types).
///         size = 8,
///         // Offset of field in bits, starting from least significant bit.
///         offset = 0,
///         // Mark this type as non-zero (validated at compile time).
///         non_zero,
///         // Control generation of get method.
///         get(vis = "pub", rename = "field", skip = false),
///         // Control generation of update method.
///         with(vis = "pub", rename = "with_field", skip = false),
///     )]
///     field: NonZeroU8,
/// }
/// # }
/// ```
#[doc(inline)]
pub use ribbit_derive::Pack;

#[doc(no_inline)]
pub use core::marker::PhantomData;
#[doc(no_inline)]
pub use core::num::NonZeroI128;
#[doc(no_inline)]
pub use core::num::NonZeroI16;
#[doc(no_inline)]
pub use core::num::NonZeroI32;
#[doc(no_inline)]
pub use core::num::NonZeroI64;
#[doc(no_inline)]
pub use core::num::NonZeroI8;
#[doc(no_inline)]
pub use core::num::NonZeroU128;
#[doc(no_inline)]
pub use core::num::NonZeroU16;
#[doc(no_inline)]
pub use core::num::NonZeroU32;
#[doc(no_inline)]
pub use core::num::NonZeroU64;
#[doc(no_inline)]
pub use core::num::NonZeroU8;
#[doc(no_inline)]
pub use core::primitive::bool;
#[doc(no_inline)]
pub use core::primitive::i128;
#[doc(no_inline)]
pub use core::primitive::i16;
#[doc(no_inline)]
pub use core::primitive::i32;
#[doc(no_inline)]
pub use core::primitive::i64;
#[doc(no_inline)]
pub use core::primitive::i8;
#[doc(no_inline)]
pub use core::primitive::u128;
#[doc(no_inline)]
pub use core::primitive::u16;
#[doc(no_inline)]
pub use core::primitive::u32;
#[doc(no_inline)]
pub use core::primitive::u64;
#[doc(no_inline)]
pub use core::primitive::u8;

#[doc(no_inline)]
pub use arbitrary_int::i1;
#[doc(no_inline)]
pub use arbitrary_int::i10;
#[doc(no_inline)]
pub use arbitrary_int::i100;
#[doc(no_inline)]
pub use arbitrary_int::i101;
#[doc(no_inline)]
pub use arbitrary_int::i102;
#[doc(no_inline)]
pub use arbitrary_int::i103;
#[doc(no_inline)]
pub use arbitrary_int::i104;
#[doc(no_inline)]
pub use arbitrary_int::i105;
#[doc(no_inline)]
pub use arbitrary_int::i106;
#[doc(no_inline)]
pub use arbitrary_int::i107;
#[doc(no_inline)]
pub use arbitrary_int::i108;
#[doc(no_inline)]
pub use arbitrary_int::i109;
#[doc(no_inline)]
pub use arbitrary_int::i11;
#[doc(no_inline)]
pub use arbitrary_int::i110;
#[doc(no_inline)]
pub use arbitrary_int::i111;
#[doc(no_inline)]
pub use arbitrary_int::i112;
#[doc(no_inline)]
pub use arbitrary_int::i113;
#[doc(no_inline)]
pub use arbitrary_int::i114;
#[doc(no_inline)]
pub use arbitrary_int::i115;
#[doc(no_inline)]
pub use arbitrary_int::i116;
#[doc(no_inline)]
pub use arbitrary_int::i117;
#[doc(no_inline)]
pub use arbitrary_int::i118;
#[doc(no_inline)]
pub use arbitrary_int::i119;
#[doc(no_inline)]
pub use arbitrary_int::i12;
#[doc(no_inline)]
pub use arbitrary_int::i120;
#[doc(no_inline)]
pub use arbitrary_int::i121;
#[doc(no_inline)]
pub use arbitrary_int::i122;
#[doc(no_inline)]
pub use arbitrary_int::i123;
#[doc(no_inline)]
pub use arbitrary_int::i124;
#[doc(no_inline)]
pub use arbitrary_int::i125;
#[doc(no_inline)]
pub use arbitrary_int::i126;
#[doc(no_inline)]
pub use arbitrary_int::i127;
#[doc(no_inline)]
pub use arbitrary_int::i13;
#[doc(no_inline)]
pub use arbitrary_int::i14;
#[doc(no_inline)]
pub use arbitrary_int::i15;
#[doc(no_inline)]
pub use arbitrary_int::i17;
#[doc(no_inline)]
pub use arbitrary_int::i18;
#[doc(no_inline)]
pub use arbitrary_int::i19;
#[doc(no_inline)]
pub use arbitrary_int::i2;
#[doc(no_inline)]
pub use arbitrary_int::i20;
#[doc(no_inline)]
pub use arbitrary_int::i21;
#[doc(no_inline)]
pub use arbitrary_int::i22;
#[doc(no_inline)]
pub use arbitrary_int::i23;
#[doc(no_inline)]
pub use arbitrary_int::i24;
#[doc(no_inline)]
pub use arbitrary_int::i25;
#[doc(no_inline)]
pub use arbitrary_int::i26;
#[doc(no_inline)]
pub use arbitrary_int::i27;
#[doc(no_inline)]
pub use arbitrary_int::i28;
#[doc(no_inline)]
pub use arbitrary_int::i29;
#[doc(no_inline)]
pub use arbitrary_int::i3;
#[doc(no_inline)]
pub use arbitrary_int::i30;
#[doc(no_inline)]
pub use arbitrary_int::i31;
#[doc(no_inline)]
pub use arbitrary_int::i33;
#[doc(no_inline)]
pub use arbitrary_int::i34;
#[doc(no_inline)]
pub use arbitrary_int::i35;
#[doc(no_inline)]
pub use arbitrary_int::i36;
#[doc(no_inline)]
pub use arbitrary_int::i37;
#[doc(no_inline)]
pub use arbitrary_int::i38;
#[doc(no_inline)]
pub use arbitrary_int::i39;
#[doc(no_inline)]
pub use arbitrary_int::i4;
#[doc(no_inline)]
pub use arbitrary_int::i40;
#[doc(no_inline)]
pub use arbitrary_int::i41;
#[doc(no_inline)]
pub use arbitrary_int::i42;
#[doc(no_inline)]
pub use arbitrary_int::i43;
#[doc(no_inline)]
pub use arbitrary_int::i44;
#[doc(no_inline)]
pub use arbitrary_int::i45;
#[doc(no_inline)]
pub use arbitrary_int::i46;
#[doc(no_inline)]
pub use arbitrary_int::i47;
#[doc(no_inline)]
pub use arbitrary_int::i48;
#[doc(no_inline)]
pub use arbitrary_int::i49;
#[doc(no_inline)]
pub use arbitrary_int::i5;
#[doc(no_inline)]
pub use arbitrary_int::i50;
#[doc(no_inline)]
pub use arbitrary_int::i51;
#[doc(no_inline)]
pub use arbitrary_int::i52;
#[doc(no_inline)]
pub use arbitrary_int::i53;
#[doc(no_inline)]
pub use arbitrary_int::i54;
#[doc(no_inline)]
pub use arbitrary_int::i55;
#[doc(no_inline)]
pub use arbitrary_int::i56;
#[doc(no_inline)]
pub use arbitrary_int::i57;
#[doc(no_inline)]
pub use arbitrary_int::i58;
#[doc(no_inline)]
pub use arbitrary_int::i59;
#[doc(no_inline)]
pub use arbitrary_int::i6;
#[doc(no_inline)]
pub use arbitrary_int::i60;
#[doc(no_inline)]
pub use arbitrary_int::i61;
#[doc(no_inline)]
pub use arbitrary_int::i62;
#[doc(no_inline)]
pub use arbitrary_int::i63;
#[doc(no_inline)]
pub use arbitrary_int::i65;
#[doc(no_inline)]
pub use arbitrary_int::i66;
#[doc(no_inline)]
pub use arbitrary_int::i67;
#[doc(no_inline)]
pub use arbitrary_int::i68;
#[doc(no_inline)]
pub use arbitrary_int::i69;
#[doc(no_inline)]
pub use arbitrary_int::i7;
#[doc(no_inline)]
pub use arbitrary_int::i70;
#[doc(no_inline)]
pub use arbitrary_int::i71;
#[doc(no_inline)]
pub use arbitrary_int::i72;
#[doc(no_inline)]
pub use arbitrary_int::i73;
#[doc(no_inline)]
pub use arbitrary_int::i74;
#[doc(no_inline)]
pub use arbitrary_int::i75;
#[doc(no_inline)]
pub use arbitrary_int::i76;
#[doc(no_inline)]
pub use arbitrary_int::i77;
#[doc(no_inline)]
pub use arbitrary_int::i78;
#[doc(no_inline)]
pub use arbitrary_int::i79;
#[doc(no_inline)]
pub use arbitrary_int::i80;
#[doc(no_inline)]
pub use arbitrary_int::i81;
#[doc(no_inline)]
pub use arbitrary_int::i82;
#[doc(no_inline)]
pub use arbitrary_int::i83;
#[doc(no_inline)]
pub use arbitrary_int::i84;
#[doc(no_inline)]
pub use arbitrary_int::i85;
#[doc(no_inline)]
pub use arbitrary_int::i86;
#[doc(no_inline)]
pub use arbitrary_int::i87;
#[doc(no_inline)]
pub use arbitrary_int::i88;
#[doc(no_inline)]
pub use arbitrary_int::i89;
#[doc(no_inline)]
pub use arbitrary_int::i9;
#[doc(no_inline)]
pub use arbitrary_int::i90;
#[doc(no_inline)]
pub use arbitrary_int::i91;
#[doc(no_inline)]
pub use arbitrary_int::i92;
#[doc(no_inline)]
pub use arbitrary_int::i93;
#[doc(no_inline)]
pub use arbitrary_int::i94;
#[doc(no_inline)]
pub use arbitrary_int::i95;
#[doc(no_inline)]
pub use arbitrary_int::i96;
#[doc(no_inline)]
pub use arbitrary_int::i97;
#[doc(no_inline)]
pub use arbitrary_int::i98;
#[doc(no_inline)]
pub use arbitrary_int::i99;
#[doc(no_inline)]
pub use arbitrary_int::traits::Integer;
#[doc(no_inline)]
pub use arbitrary_int::u1;
#[doc(no_inline)]
pub use arbitrary_int::u10;
#[doc(no_inline)]
pub use arbitrary_int::u100;
#[doc(no_inline)]
pub use arbitrary_int::u101;
#[doc(no_inline)]
pub use arbitrary_int::u102;
#[doc(no_inline)]
pub use arbitrary_int::u103;
#[doc(no_inline)]
pub use arbitrary_int::u104;
#[doc(no_inline)]
pub use arbitrary_int::u105;
#[doc(no_inline)]
pub use arbitrary_int::u106;
#[doc(no_inline)]
pub use arbitrary_int::u107;
#[doc(no_inline)]
pub use arbitrary_int::u108;
#[doc(no_inline)]
pub use arbitrary_int::u109;
#[doc(no_inline)]
pub use arbitrary_int::u11;
#[doc(no_inline)]
pub use arbitrary_int::u110;
#[doc(no_inline)]
pub use arbitrary_int::u111;
#[doc(no_inline)]
pub use arbitrary_int::u112;
#[doc(no_inline)]
pub use arbitrary_int::u113;
#[doc(no_inline)]
pub use arbitrary_int::u114;
#[doc(no_inline)]
pub use arbitrary_int::u115;
#[doc(no_inline)]
pub use arbitrary_int::u116;
#[doc(no_inline)]
pub use arbitrary_int::u117;
#[doc(no_inline)]
pub use arbitrary_int::u118;
#[doc(no_inline)]
pub use arbitrary_int::u119;
#[doc(no_inline)]
pub use arbitrary_int::u12;
#[doc(no_inline)]
pub use arbitrary_int::u120;
#[doc(no_inline)]
pub use arbitrary_int::u121;
#[doc(no_inline)]
pub use arbitrary_int::u122;
#[doc(no_inline)]
pub use arbitrary_int::u123;
#[doc(no_inline)]
pub use arbitrary_int::u124;
#[doc(no_inline)]
pub use arbitrary_int::u125;
#[doc(no_inline)]
pub use arbitrary_int::u126;
#[doc(no_inline)]
pub use arbitrary_int::u127;
#[doc(no_inline)]
pub use arbitrary_int::u13;
#[doc(no_inline)]
pub use arbitrary_int::u14;
#[doc(no_inline)]
pub use arbitrary_int::u15;
#[doc(no_inline)]
pub use arbitrary_int::u17;
#[doc(no_inline)]
pub use arbitrary_int::u18;
#[doc(no_inline)]
pub use arbitrary_int::u19;
#[doc(no_inline)]
pub use arbitrary_int::u2;
#[doc(no_inline)]
pub use arbitrary_int::u20;
#[doc(no_inline)]
pub use arbitrary_int::u21;
#[doc(no_inline)]
pub use arbitrary_int::u22;
#[doc(no_inline)]
pub use arbitrary_int::u23;
#[doc(no_inline)]
pub use arbitrary_int::u24;
#[doc(no_inline)]
pub use arbitrary_int::u25;
#[doc(no_inline)]
pub use arbitrary_int::u26;
#[doc(no_inline)]
pub use arbitrary_int::u27;
#[doc(no_inline)]
pub use arbitrary_int::u28;
#[doc(no_inline)]
pub use arbitrary_int::u29;
#[doc(no_inline)]
pub use arbitrary_int::u3;
#[doc(no_inline)]
pub use arbitrary_int::u30;
#[doc(no_inline)]
pub use arbitrary_int::u31;
#[doc(no_inline)]
pub use arbitrary_int::u33;
#[doc(no_inline)]
pub use arbitrary_int::u34;
#[doc(no_inline)]
pub use arbitrary_int::u35;
#[doc(no_inline)]
pub use arbitrary_int::u36;
#[doc(no_inline)]
pub use arbitrary_int::u37;
#[doc(no_inline)]
pub use arbitrary_int::u38;
#[doc(no_inline)]
pub use arbitrary_int::u39;
#[doc(no_inline)]
pub use arbitrary_int::u4;
#[doc(no_inline)]
pub use arbitrary_int::u40;
#[doc(no_inline)]
pub use arbitrary_int::u41;
#[doc(no_inline)]
pub use arbitrary_int::u42;
#[doc(no_inline)]
pub use arbitrary_int::u43;
#[doc(no_inline)]
pub use arbitrary_int::u44;
#[doc(no_inline)]
pub use arbitrary_int::u45;
#[doc(no_inline)]
pub use arbitrary_int::u46;
#[doc(no_inline)]
pub use arbitrary_int::u47;
#[doc(no_inline)]
pub use arbitrary_int::u48;
#[doc(no_inline)]
pub use arbitrary_int::u49;
#[doc(no_inline)]
pub use arbitrary_int::u5;
#[doc(no_inline)]
pub use arbitrary_int::u50;
#[doc(no_inline)]
pub use arbitrary_int::u51;
#[doc(no_inline)]
pub use arbitrary_int::u52;
#[doc(no_inline)]
pub use arbitrary_int::u53;
#[doc(no_inline)]
pub use arbitrary_int::u54;
#[doc(no_inline)]
pub use arbitrary_int::u55;
#[doc(no_inline)]
pub use arbitrary_int::u56;
#[doc(no_inline)]
pub use arbitrary_int::u57;
#[doc(no_inline)]
pub use arbitrary_int::u58;
#[doc(no_inline)]
pub use arbitrary_int::u59;
#[doc(no_inline)]
pub use arbitrary_int::u6;
#[doc(no_inline)]
pub use arbitrary_int::u60;
#[doc(no_inline)]
pub use arbitrary_int::u61;
#[doc(no_inline)]
pub use arbitrary_int::u62;
#[doc(no_inline)]
pub use arbitrary_int::u63;
#[doc(no_inline)]
pub use arbitrary_int::u65;
#[doc(no_inline)]
pub use arbitrary_int::u66;
#[doc(no_inline)]
pub use arbitrary_int::u67;
#[doc(no_inline)]
pub use arbitrary_int::u68;
#[doc(no_inline)]
pub use arbitrary_int::u69;
#[doc(no_inline)]
pub use arbitrary_int::u7;
#[doc(no_inline)]
pub use arbitrary_int::u70;
#[doc(no_inline)]
pub use arbitrary_int::u71;
#[doc(no_inline)]
pub use arbitrary_int::u72;
#[doc(no_inline)]
pub use arbitrary_int::u73;
#[doc(no_inline)]
pub use arbitrary_int::u74;
#[doc(no_inline)]
pub use arbitrary_int::u75;
#[doc(no_inline)]
pub use arbitrary_int::u76;
#[doc(no_inline)]
pub use arbitrary_int::u77;
#[doc(no_inline)]
pub use arbitrary_int::u78;
#[doc(no_inline)]
pub use arbitrary_int::u79;
#[doc(no_inline)]
pub use arbitrary_int::u80;
#[doc(no_inline)]
pub use arbitrary_int::u81;
#[doc(no_inline)]
pub use arbitrary_int::u82;
#[doc(no_inline)]
pub use arbitrary_int::u83;
#[doc(no_inline)]
pub use arbitrary_int::u84;
#[doc(no_inline)]
pub use arbitrary_int::u85;
#[doc(no_inline)]
pub use arbitrary_int::u86;
#[doc(no_inline)]
pub use arbitrary_int::u87;
#[doc(no_inline)]
pub use arbitrary_int::u88;
#[doc(no_inline)]
pub use arbitrary_int::u89;
#[doc(no_inline)]
pub use arbitrary_int::u9;
#[doc(no_inline)]
pub use arbitrary_int::u90;
#[doc(no_inline)]
pub use arbitrary_int::u91;
#[doc(no_inline)]
pub use arbitrary_int::u92;
#[doc(no_inline)]
pub use arbitrary_int::u93;
#[doc(no_inline)]
pub use arbitrary_int::u94;
#[doc(no_inline)]
pub use arbitrary_int::u95;
#[doc(no_inline)]
pub use arbitrary_int::u96;
#[doc(no_inline)]
pub use arbitrary_int::u97;
#[doc(no_inline)]
pub use arbitrary_int::u98;
#[doc(no_inline)]
pub use arbitrary_int::u99;

/// Support for atomic operations on packed representations.
#[cfg(feature = "atomic")]
pub mod atomic;
#[cfg(feature = "atomic")]
#[doc(inline)]
pub use atomic::Atomic;

/// Internal type alias for `()`.
pub type Unit = ();

/// Convenience type alias for the packed representation of `T`.
pub type Packed<T> = <T as Pack>::Packed;

/// Convenience type alias for the unpacked representation of `T`.
pub type Unpacked<T> = <T as Unpack>::Unpacked;

/// Marks a type that can be packed into `BITS`.
///
/// Currently supports sizes up to 128 bits.
///
/// # Safety
///
/// This trait should only be implemented by the `pack` macro.
pub unsafe trait Pack: Copy {
    type Packed: Unpack<Unpacked = Self>;

    fn pack(self) -> Self::Packed;
}

/// Marks a packed type with size `BITS`.
///
/// Currently supports sizes up to 128 bits.
///
/// # Safety
///
/// This trait should only be implemented by the `pack` macro.
///
/// Implementer must ensure:
/// - Type has size `BITS`
/// - Size and alignment of `Self::Loose` is the same as `Self`
/// - Size and alignment of `Self::Raw` is the same as `Self`
pub unsafe trait Unpack: Copy {
    /// Size of `Self::Raw` in bits.
    const BITS: usize;

    /// Unpacked representation.
    type Unpacked: Pack<Packed = Self>;

    /// Smallest native unsigned integer type that fits `Self::Raw`.
    type Loose: Loose;

    /// Raw underlying representation of a packed type.
    type Raw: Unpack<Unpacked = Self::Raw, Loose = Self::Loose, Raw = Self::Raw>;

    /// Convert to unpacked representation.
    fn unpack(self) -> Self::Unpacked;

    /// Convert from typed to raw representation.
    ///
    /// The [`Pack`](`macro@Pack`) macro implements a `const` inherent method
    /// with the same name. See [`crate::convert::packed_to_raw`] if generics
    /// are involved and `const` is required.
    fn into_raw(self) -> Self::Raw;

    /// Convert from raw to typed representation.
    ///
    /// The [`Pack`](`macro@Pack`) macro implements a `const` inherent associated function
    /// with the same name. See [`crate::convert::raw_to_packed`] if generics
    /// are involved and `const` is required.
    ///
    /// # Safety
    ///
    /// Caller must guarantee `raw` is a valid bit pattern for `Self`, e.g.,
    /// was created by a previous call to [`Unpack::into_raw`].
    unsafe fn from_raw_unchecked(raw: Self::Raw) -> Self;
}

/// Native unsigned integer type.
///
/// Used internally for `const`-compatible operations on the underlying bytes
/// of a packed type.
pub trait Loose:
    Copy + Sized + Unpack<Unpacked = Self, Loose = Self, Raw = Self> + seal::Seal
{
    const ZERO: Self;
    /// Default atomic integer type.
    #[cfg(feature = "atomic")]
    type Atomic: atomic::Raw<Self>;
}

mod seal {
    pub trait Seal {}
    impl Seal for u8 {}
    impl Seal for u16 {}
    impl Seal for u32 {}
    impl Seal for u64 {}
    #[cfg(feature = "u128")]
    impl Seal for u128 {}
}

/// Implements `const`-compatible conversions between packed and loose representations.
pub mod convert {
    use core::mem::MaybeUninit;

    use crate::Loose;
    use crate::Unpack;

    union Transmute<T: Unpack> {
        packed: T,
        loose: T::Loose,
        raw: T::Raw,
    }

    /// Convert from a packed struct to a native integer type.
    #[doc(hidden)]
    #[inline]
    pub const fn packed_to_loose<T: Unpack>(packed: T) -> T::Loose {
        // Zero sized types are the only types where the
        // loose and packed representations differ.
        if const { T::BITS == 0 } {
            assert!(core::mem::size_of::<T>() == 0);
            assert!(core::mem::align_of::<T>() == 1);

            assert!(core::mem::size_of::<T::Loose>() == 1);
            assert!(core::mem::align_of::<T::Loose>() == 1);
            return T::Loose::ZERO;
        } else {
            assert_size_align::<T, T::Loose>()
        }

        // SAFETY: `T` and `T::Loose` have the same layout
        unsafe { Transmute { packed }.loose }
    }

    /// `const`-compatible version of [`Unpack::into_raw`].
    #[inline]
    pub const fn packed_to_raw<T: Unpack>(packed: T) -> T::Raw {
        const { assert_size_align::<T, T::Raw>() }

        // SAFETY: `T` and `T::Raw` have the same layout
        unsafe { Transmute { packed }.raw }
    }

    /// Convert from a native integer type to a packed struct.
    ///
    /// # Safety
    ///
    /// Caller must guarantee that `loose` is a valid bit pattern for type `T`.
    #[doc(hidden)]
    #[inline]
    pub const unsafe fn loose_to_packed<T: Unpack>(loose: T::Loose) -> T {
        // Zero sized types are the only types where the
        // loose and packed representations differ.
        if const { T::BITS == 0 } {
            assert!(core::mem::size_of::<T>() == 0);
            assert!(core::mem::align_of::<T>() == 1);

            assert!(core::mem::size_of::<T::Loose>() == 1);
            assert!(core::mem::align_of::<T::Loose>() == 1);
            return core::mem::transmute_copy::<(), T>(&());
        } else {
            assert_size_align::<T::Loose, T>()
        }

        // SAFETY: `T` and `T::Loose` have the same layout, and caller guarantees bit pattern is valid
        unsafe { Transmute { loose }.packed }
    }

    /// `const`-compatible version of [`Unpack::from_raw_unchecked`].
    ///
    /// # Safety
    ///
    /// Caller must guarantee that `raw` is a valid bit pattern for type `T`.
    #[inline]
    pub const unsafe fn raw_to_packed<T: Unpack>(raw: T::Raw) -> T {
        const { assert_size_align::<T::Raw, T>() }

        // SAFETY: `T` and `T::Raw` have the same layout, and caller guarantees bit pattern is valid
        unsafe { Transmute { raw }.packed }
    }

    #[repr(C)]
    union Convert<F: Loose, I: Loose> {
        from: F,
        into: I,
    }

    /// Convert between two generic native integer types.
    #[doc(hidden)]
    #[allow(private_bounds)]
    #[inline]
    pub const fn loose_to_loose<F: Loose, I: Loose>(from: F) -> I {
        // SAFETY: `Loose` is only implemented for native integer types.
        unsafe {
            let size_from = const { core::mem::size_of::<F>() };
            let size_into = const { core::mem::size_of::<I>() };

            // Easy case: not possible to read uninitialized memory
            if size_from >= size_into {
                return Convert { from }.into;
            }

            let mut zeroed = MaybeUninit::<Convert<F, I>>::zeroed();

            // NOTE: assumes const evaluation is run with the target
            // endianness--can't find info on whether this is true
            let offset = if cfg!(target_endian = "little") {
                0
            } else {
                size_into - size_from
            };

            // Need raw pointer write (as opposed to `zeroed.write(Convert { from })`)
            // to avoid clobbering zeroed memory with uninitialized padding.
            //
            // https://google.github.io/learn_unsafe_rust/advanced_unsafety/uninitialized.html#padding
            zeroed.as_mut_ptr().byte_add(offset).cast::<F>().write(from);
            zeroed.assume_init().into
        }
    }

    const fn assert_size_align<T, U>() {
        assert!(core::mem::size_of::<T>() == core::mem::size_of::<U>());
        assert!(core::mem::align_of::<T>() == core::mem::align_of::<U>());
    }
}

macro_rules! impl_pack {
    ($tight:ty) => {
        unsafe impl Pack for $tight {
            type Packed = Self;

            #[inline]
            fn pack(self) -> Self::Packed {
                self
            }
        }
    };
}

macro_rules! impl_unpack {
    ($tight:ty, $bits:expr, $loose:ty) => {
        unsafe impl Unpack for $tight {
            const BITS: usize = $bits;
            type Unpacked = Self;
            type Loose = $loose;
            type Raw = Self;

            #[inline]
            fn unpack(self) -> Self::Unpacked {
                const {
                    assert!(core::mem::size_of::<Self>() == core::mem::size_of::<Self::Loose>());
                    assert!(core::mem::align_of::<Self>() == core::mem::align_of::<Self::Loose>());

                    assert!(core::mem::size_of::<Self>() == core::mem::size_of::<Self::Raw>());
                    assert!(core::mem::align_of::<Self>() == core::mem::align_of::<Self::Raw>());
                }

                self
            }

            #[inline]
            fn into_raw(self) -> Self::Raw {
                self
            }

            #[inline]
            unsafe fn from_raw_unchecked(raw: Self::Raw) -> Self {
                raw
            }
        }
    };
}

#[rustfmt::skip]
macro_rules! impl_impl_number {
    ($name:ident, $unsigned_loose:ty, $signed_loose:ty, $loose_bits:expr, $dollar:tt) => {
        impl_pack!($unsigned_loose);
        impl_unpack!($unsigned_loose, $loose_bits, $unsigned_loose);

        impl_pack!($signed_loose);
        impl_unpack!($signed_loose, $loose_bits, $unsigned_loose);

        macro_rules! $name {
            ($dollar($unsigned:ident, $signed:ident: $bits:expr),* $dollar(,)?) => {
                $dollar(
                    impl_pack!($unsigned);
                    impl_unpack!($unsigned, $bits, $unsigned_loose);

                    impl_pack!($signed);
                    impl_unpack!($signed, $bits, $unsigned_loose);
                )*
            };
        }
    };
}

impl_pack!(());

unsafe impl Unpack for () {
    const BITS: usize = 0;
    type Unpacked = Self;
    type Loose = u8;
    type Raw = ();

    #[inline]
    fn unpack(self) -> Self::Unpacked {}

    #[inline]
    fn into_raw(self) -> Self::Raw {}

    #[inline]
    unsafe fn from_raw_unchecked(_: Self::Raw) -> Self {}
}

unsafe impl<T> Pack for PhantomData<T> {
    type Packed = Self;

    #[inline]
    fn pack(self) -> Self::Packed {
        self
    }
}

unsafe impl<T> Unpack for PhantomData<T> {
    const BITS: usize = 0;
    type Unpacked = PhantomData<T>;
    type Loose = u8;
    type Raw = Self;

    #[inline]
    fn unpack(self) -> Self::Unpacked {
        self
    }

    #[inline]
    fn into_raw(self) -> Self::Raw {
        self
    }

    #[inline]
    unsafe fn from_raw_unchecked(raw: Self::Raw) -> Self {
        raw
    }
}

impl_pack!(bool);

unsafe impl Unpack for bool {
    const BITS: usize = 1;
    type Unpacked = bool;
    type Loose = u8;
    type Raw = bool;

    #[inline]
    fn unpack(self) -> Self::Unpacked {
        self
    }

    #[inline]
    fn into_raw(self) -> Self::Raw {
        self
    }

    #[inline]
    unsafe fn from_raw_unchecked(raw: Self::Raw) -> Self {
        raw
    }
}

impl Loose for u8 {
    const ZERO: Self = 0;
    #[cfg(feature = "atomic")]
    type Atomic = atomic::AtomicU8;
}

impl_impl_number!(impl_u8, u8, i8, 8, $);
impl_u8!(
    u1, i1: 1,
    u2, i2: 2,
    u3, i3: 3,
    u4, i4: 4,
    u5, i5: 5,
    u6, i6: 6,
    u7, i7: 7,
);

impl Loose for u16 {
    const ZERO: Self = 0;
    #[cfg(feature = "atomic")]
    type Atomic = atomic::AtomicU16;
}

impl_impl_number!(impl_u16, u16, i16, 16, $);
impl_u16!(
    u9, i9: 9,
    u10, i10: 10,
    u11, i11: 11,
    u12, i12: 12,
    u13, i13: 13,
    u14, i14: 14,
    u15, i15: 15,
);

impl Loose for u32 {
    const ZERO: Self = 0;
    #[cfg(feature = "atomic")]
    type Atomic = atomic::AtomicU32;
}

impl_impl_number!(impl_u32, u32, i32, 32, $);
impl_u32!(
    u17, i17: 17,
    u18, i18: 18,
    u19, i19: 19,
    u20, i20: 20,
    u21, i21: 21,
    u22, i22: 22,
    u23, i23: 23,
    u24, i24: 24,
    u25, i25: 25,
    u26, i26: 26,
    u27, i27: 27,
    u28, i28: 28,
    u29, i29: 29,
    u30, i30: 30,
    u31, i31: 31,
);

impl Loose for u64 {
    const ZERO: Self = 0;
    #[cfg(feature = "atomic")]
    type Atomic = atomic::AtomicU64;
}

impl_impl_number!(impl_u64, u64, i64, 64, $);
impl_u64!(
    u33, i33: 33,
    u34, i34: 34,
    u35, i35: 35,
    u36, i36: 36,
    u37, i37: 37,
    u38, i38: 38,
    u39, i39: 39,
    u40, i40: 40,
    u41, i41: 41,
    u42, i42: 42,
    u43, i43: 43,
    u44, i44: 44,
    u45, i45: 45,
    u46, i46: 46,
    u47, i47: 47,
    u48, i48: 48,
    u49, i49: 49,
    u50, i50: 50,
    u51, i51: 51,
    u52, i52: 52,
    u53, i53: 53,
    u54, i54: 54,
    u55, i55: 55,
    u56, i56: 56,
    u57, i57: 57,
    u58, i58: 58,
    u59, i59: 59,
    u60, i60: 60,
    u61, i61: 61,
    u62, i62: 62,
    u63, i63: 63,
);

#[cfg(feature = "u128")]
impl Loose for u128 {
    const ZERO: Self = 0;
    #[cfg(feature = "atomic")]
    type Atomic = atomic::AtomicU128;
}

#[cfg(feature = "u128")]
impl_impl_number!(impl_u128, u128, i128, 128, $);
#[cfg(feature = "u128")]
impl_u128!(
    u65, i65: 65,
    u66, i66: 66,
    u67, i67: 67,
    u68, i68: 68,
    u69, i69: 69,
    u70, i70: 70,
    u71, i71: 71,
    u72, i72: 72,
    u73, i73: 73,
    u74, i74: 74,
    u75, i75: 75,
    u76, i76: 76,
    u77, i77: 77,
    u78, i78: 78,
    u79, i79: 79,
    u80, i80: 80,
    u81, i81: 81,
    u82, i82: 82,
    u83, i83: 83,
    u84, i84: 84,
    u85, i85: 85,
    u86, i86: 86,
    u87, i87: 87,
    u88, i88: 88,
    u89, i89: 89,
    u90, i90: 90,
    u91, i91: 91,
    u92, i92: 92,
    u93, i93: 93,
    u94, i94: 94,
    u95, i95: 95,
    u96, i96: 96,
    u97, i97: 97,
    u98, i98: 98,
    u99, i99: 99,
    u100, i100: 100,
    u101, i101: 101,
    u102, i102: 102,
    u103, i103: 103,
    u104, i104: 104,
    u105, i105: 105,
    u106, i106: 106,
    u107, i107: 107,
    u108, i108: 108,
    u109, i109: 109,
    u110, i110: 110,
    u111, i111: 111,
    u112, i112: 112,
    u113, i113: 113,
    u114, i114: 114,
    u115, i115: 115,
    u116, i116: 116,
    u117, i117: 117,
    u118, i118: 118,
    u119, i119: 119,
    u120, i120: 120,
    u121, i121: 121,
    u122, i122: 122,
    u123, i123: 123,
    u124, i124: 124,
    u125, i125: 125,
    u126, i126: 126,
    u127, i127: 127,
);

/// Marker trait asserting that values of this type cannot be zero, *and*
/// that Rust is aware of this niche. Only implemented for standard library
/// `NonZero` types.
///
/// # Safety
///
/// Implementer must guarantee that zero is not a valid bit pattern for this type,
/// and that Rust is aware of this niche.
#[allow(private_bounds)]
unsafe trait NonZero {}

macro_rules! impl_non_zero {
    ($unsigned:ty, $signed:ty, $loose:ty, $bits:expr) => {
        impl_pack!($unsigned);
        impl_unpack!($unsigned, $bits, $loose);
        unsafe impl NonZero for $unsigned {}

        impl_pack!($signed);
        impl_unpack!($signed, $bits, $loose);
        unsafe impl NonZero for $signed {}
    };
}

impl_non_zero!(NonZeroU8, NonZeroI8, u8, 8);
impl_non_zero!(NonZeroU16, NonZeroI16, u16, 16);
impl_non_zero!(NonZeroU32, NonZeroI32, u32, 32);
impl_non_zero!(NonZeroU64, NonZeroI64, u64, 64);
#[cfg(feature = "u128")]
impl_non_zero!(NonZeroU128, NonZeroI128, u128, 128);

unsafe impl<T> Pack for Option<T>
where
    T: Pack,
    <T::Packed as Unpack>::Raw: NonZero,
{
    type Packed = Option<T::Packed>;
    fn pack(self) -> Self::Packed {
        self.map(|unpacked| unpacked.pack())
    }
}

unsafe impl<T> Unpack for Option<T>
where
    T: Unpack<Raw: NonZero>,
{
    const BITS: usize = T::BITS;
    type Unpacked = Option<T::Unpacked>;
    type Loose = T::Loose;
    type Raw = T::Loose;

    #[inline]
    fn unpack(self) -> Self::Unpacked {
        self.map(|packed| packed.unpack())
    }

    #[inline]
    fn into_raw(self) -> Self::Raw {
        const {
            assert!(size_of::<Self>() == size_of::<T>());
            assert!(align_of::<Self>() == align_of::<T>());
        }

        // SAFETY: `T::Raw` implements `NonZero`, so Option<T> uses zero niche
        unsafe { core::mem::transmute_copy(&self) }
    }

    #[inline]
    unsafe fn from_raw_unchecked(raw: Self::Raw) -> Self {
        const {
            assert!(size_of::<Self>() == size_of::<T>());
            assert!(align_of::<Self>() == align_of::<T>());
        }

        // SAFETY: `T::Raw` implements `NonZero`, so Option<T> uses zero niche
        unsafe { core::mem::transmute_copy(&raw) }
    }
}

#[doc(hidden)]
pub mod private {
    /// `const` assertion that `T` is backed by a non-zero type.
    #[expect(private_bounds)]
    pub const fn assert_non_zero<T>()
    where
        T: crate::Pack,
        <T::Packed as crate::Unpack>::Raw: crate::NonZero,
    {
    }

    /// `const` assertion that `T` is exactly `expected` bits.
    pub const fn assert_size_eq<T>(expected: usize)
    where
        T: crate::Pack,
    {
        assert!(
            expected == <T::Packed as crate::Unpack>::BITS,
            "Annotated size does not equal actual size",
        )
    }

    /// `const` assertion that `T` is at least `expected` bits.
    pub const fn assert_size_ge<T>(expected: usize)
    where
        T: crate::Pack,
    {
        assert!(
            expected >= <T::Packed as crate::Unpack>::BITS,
            "Annotated size is less than actual size",
        )
    }
}
