// Copyright 2025 Gabriel Bjørnager Jensen.

#![doc(html_logo_url = "https://gitlab.com/bjoernager/multitype/-/raw/master/doc-icon.svg")]

//! MultiType is a crate for generalising fundamental types via traits.
//!
//! MultiType provideds traits such as [`Uint`](Uint) and [`Float`](Float) traits to abstract over a set of equivalent primitive types.
//! These traits are intended to provide one-to-one copies of the interfaces that the primitive types define.
//!
//! # Overview
//!
//! The complete list of abstraction traits is:
//!
//! * [`Int`]
//!   * [`IntLeast16`]
//!   * [`IntLeast32`]
//!   * [`IntLeast64`]
//! * [`Uint`]
//!   * [`UintLeast16`]
//!   * [`UintLeast32`]
//!   * [`UintLeast64`]
//! * [`Float`]
//!   * [`FloatLeast32`]
#![cfg_attr(feature = "f128", doc = "  * [`FloatLeast64`]")]
#![cfg_attr(feature = "std", doc = "  * [`StdFloat`]")]
//! * [`Array`]
//!
//! Any given type may implement at most *one* of the aforementioned trait groups; thus, for example, any type that implemets `Float` can be assumed to possibly implement `FloatLeast32` but never `Uint`.
//!
//! For the sake of compatibility with <code>{[f16], [f32], [f64], [f128]}::[to_int_unchecked](f64::to_int_unchecked)</code>, we also define our own `FloatToInt` trait.
//!
//! Note that all traits provided by this crate are sealed and cannot be implemented by third-party crates (at least currently).
//!
//! # Arithmetic types
//!
//! MultiType defines different traits for generalising arithmetic types:
//!
//! * [`Int`](Int) for [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], and [`isize`]
//! * [`Uint`](Uint) for [`u8`], [`u16`], [`u32`], [`u64`], [`u128`], and [`usize`]
//! * [`Float`](Float) for [`f16`], [`f32`], [`f64`], and [`f128`]
//!
#![cfg_attr(feature = "std", doc = "Furthermore, `StdFloat` extends the `Float` trait with functionality that is typically only available in `std`'s floating-point types.")]
//!
//! ## Sized, arithmetic types
//!
//! The basic, arithmetic traits guarantee a minimum size that is equivalent to the smallest member of its group, e.g. `Uint` is at least `u8` and `Float` is at least `f16`.
//!
//! Additionally, these three arithmetic traits have subtraits that guarantee wider types, for example:
//!
//! * `i16` and wider implement [`IntLeast16`](IntLeast16)
//! * `i32` and wider implement [`IntLeast32`](IntLeast32)
//! * Etc.
//!
//! Extremely-wide traits, e.g. `IntLeast8` or `IntLeast128`, are considered redundant and are thus not provided.
//!
//! # Array types
//!
//! MultiType also provides the [`Array`](array::Array) trait for generalising array types -- most often over their length.
//!
//! An example of this trait's usecase is actually in this crate:
//! Take, for instance, the definition of [`Uint`](Uint): It has a `Bytes` associated type that is used by the bytewise constructors and destructors:
//!
//! ```rust
//! pub unsafe trait Uint: /* .. */ {
//!     type Bytes;
//!
//!     fn from_ne_bytes(bytes: Self::Bytes) -> Self;
//!
//!     fn to_ne_bytes(self) -> Self::Bytes;
//!
//!     // ..
//! }
//! ```
//!
//! Now, anyone that would want to use the output of [`to_ne_bytes`](Uint::to_ne_bytes) wouldn't really have that many choices with regard to what to do with it.
//! So, MultiType defines the `Array` trait:
//!
//! ```rust
//! use multitype::Array;
//!
//! pub unsafe trait Uint: /* .. */ {
//!     type Bytes: Array<Scalar = u8>;
//!
//!     // ..
//! }
//! ```
//!
//! With it, it's possible for users to generically use `Uint::to_ne_bytes` as an array type through the trait methods.
//!
//! # Examples
//!
//! A generic Fibonacci sequence:
//!
//! ```rust
//! use multitype::Uint;
//!
//! fn f<T: Uint>(x: T) -> T {
//!     let mut y    = T::from(0x0u8);
//!     let mut y_m1 = T::from(0x0u8);
//!     let mut y_m2 = T::from(0x1u8);
//!
#![cfg_attr(    feature = "step",  doc = "    for i in T::from(0x0u8)..x {\n")]
#![cfg_attr(not(feature = "step"), doc = "    let mut i = T::from(0x0u8);\n")]
#![cfg_attr(not(feature = "step"), doc = "    while i < x {\n")]
//!         y = y_m1 + y_m2;
//!
//!         y_m2 = y_m1;
//!         y_m1 = y;
#![cfg_attr(not(feature = "step"), doc = "\n")]
#![cfg_attr(not(feature = "step"), doc = "        i += T::from(0x1u8);\n")]
//!     }
//!
//!     y
//! }
//!
//! assert_eq!(f(0u8),   0);
//! assert_eq!(f(1u8),   1);
//!
//! assert_eq!(f(2u16),  1);
//! assert_eq!(f(3u16),  2);
//!
//! assert_eq!(f(4u32),  3);
//! assert_eq!(f(5u32),  5);
//!
//! assert_eq!(f(6u64),  8);
//! assert_eq!(f(7u64), 13);
//! ```
//!
//! Generic array indexing:
//!
//! ```rust
//! use core::f32;
//! use multitype::{Array, Float};
//!
//! fn complicated_neg<T: Float>(value: T) -> T {
//!     let mut bytes = value.to_le_bytes();
//!
//!     // Invert the sign bit -- which is always the most
//!     // significant bit of the most significant byte.
//!     *bytes.as_mut_slice().last_mut().unwrap() ^= 0b10000000;
//!
//!     T::from_le_bytes(bytes)
//! }
//!
//! assert_eq!(complicated_neg( 1.0f64), -1.0f64);
//! assert_eq!(complicated_neg(-1.0f64),  1.0f64);
//!
//! assert_eq!(complicated_neg(f32::NEG_INFINITY), f32::INFINITY);
//! ```
//!
//! # Feature flags
//!
//! Default features:
//! * `alloc`
//! * `std`
//!
//! Dependency features:
#![cfg_attr(feature = "alloc",      doc = "* `alloc`: Enables compatibility with [`alloc`] facilities\n")]
#![cfg_attr(not(feature = "alloc"), doc = "* `alloc`: Enables compatibility with `alloc` facilities\n")]
#![cfg_attr(feature = "std",        doc = "* `std`: Enables compatibility with [`std`] facilities\n")]
#![cfg_attr(not(feature = "std"),   doc = "* `std`: Enables compatibility with `std` facilities\n")]
//!
//! Unstable features:
//! * `clone_to_uninit`: Enables [`CloneToUninit`](core::clone::CloneToUninit) requirements
//! * `const_param_ty`: Enables [`ConstParamTy_`](core::marker::ConstParamTy_) requirements
//! * `f128`: Enables support for [`f128`]
//! * `f16`: Enables support for [`f16`]
//! * `freeze`: Enables [`Freeze`](core::marker::Freeze) requirements
//! * `step`: Enables [`Step`](core::iter::Step) requirements
//! * `structural_partial_eq`: Enables [`StructuralPartialEq`](core::marker::StructuralPartialEq) requirements
//! * `thin`: Enables [`Thin`](core::ptr::Thin) requirements
//! * `trusted_step`: Enables [`TrustedStep`](core::iter::TrustedStep) requirements
//! * `unstable-docs`: Enables unstable documentation features requirements
//! * `use_cloned`: Enables [`UseCloned`](core::clone::UseCloned) requirements
//!
//! Unstable features can be expected to be removed as their facilities stabilise.
//!
//! # MSRV policy
//!
//! The goal of MultiType is to provide generic traits that bind as much of the standard interfaces as possible.
//! We will attempt to backport all trivial interfaces as much as possible, but if any given interface is deemed to complicated, we will bump the MSRV to leverage it from the standard implementation.
//!
//! When `const`-compatible traits land, MultiType will implement the feature as quickly as possible.
//!
//! # Copyright & Licence.
//!
//! Copyright &#169; 2025 Gabriel Bjørnager Jensen.
//!
//! MultiType is distributed under either an MIT licence (see `LICENCE-MIT`) or version 2.0 of the Apache License (see `LICENCE-APACHE`), at your option.

#![no_std]

#![cfg_attr(feature = "use_cloned", expect(incomplete_features))]

#![cfg_attr(feature = "clone_to_uninit",       feature(clone_to_uninit))]
#![cfg_attr(feature = "const_param_ty",        feature(unsized_const_params))]
#![cfg_attr(feature = "f16",                   feature(f16))]
#![cfg_attr(feature = "f128",                  feature(f128))]
#![cfg_attr(feature = "freeze",                feature(freeze))]
#![cfg_attr(feature = "step",                  feature(step_trait))]
#![cfg_attr(feature = "structural_partial_eq", feature(structural_match))]
#![cfg_attr(feature = "thin",                  feature(ptr_metadata))]
#![cfg_attr(feature = "trusted_step",          feature(trusted_step))]
#![cfg_attr(feature = "unstable-docs",         feature(doc_cfg, intra_doc_pointers))]
#![cfg_attr(feature = "use_cloned",            feature(ergonomic_clones))]

extern crate self as multitype;

#[cfg(feature = "alloc")]
extern crate alloc;

#[cfg(feature = "std")]
extern crate std;

mod array;
mod carrying_mul_add;
mod compat;
mod disjoint_bitor;
mod float;
mod float_to_int;
mod float_least32;
mod float_least64;
mod int;
mod int_least16;
mod int_least32;
mod int_least64;
mod std_float;
mod uint;
mod uint_least16;
mod uint_least32;
mod uint_least64;

pub use array::Array;
pub use float::Float;
pub use float_least32::FloatLeast32;
pub use int::Int;
pub use int_least16::IntLeast16;
pub use int_least32::IntLeast32;
pub use int_least64::IntLeast64;
pub use uint::Uint;
pub use uint_least16::UintLeast16;
pub use uint_least32::UintLeast32;
pub use uint_least64::UintLeast64;

#[cfg(feature = "f128")]
pub use float_least64::FloatLeast64;

#[cfg(feature = "std")]
pub use std_float::StdFloat;

use carrying_mul_add::CarryingMulAdd;
use disjoint_bitor::DisjointBitOr;
use float_to_int::FloatToInt;

mod seal {
	pub trait Uint        {}
	pub trait UintLeast16 {}
	pub trait UintLeast32 {}
	pub trait UintLeast64 {}

	pub trait Int        {}
	pub trait IntLeast16 {}
	pub trait IntLeast32 {}
	pub trait IntLeast64 {}

	pub trait Float        {}
	pub trait FloatLeast32 {}

	pub trait Array {}

	#[cfg(feature = "f128")]
	pub trait FloatLeast64 {}

	#[cfg(feature = "std")]
	pub trait StdFloat {}
}
