multitype/
lib.rs

1// Copyright 2025 Gabriel Bjørnager Jensen.
2
3#![doc(html_logo_url = "https://gitlab.com/bjoernager/multitype/-/raw/master/doc-icon.svg")]
4
5//! MultiType is a crate for generalising fundamental types via traits.
6//!
7//! MultiType provideds traits such as [`Uint`](Uint) and [`Float`](Float) traits to abstract over a set of equivalent primitive types.
8//! These traits are intended to provide one-to-one copies of the interfaces that the primitive types define.
9//!
10//! # Overview
11//!
12//! The complete list of abstraction traits is:
13//!
14//! * [`Uint`](Uint)
15//!   * [`UintLeast16`](UintLeast16)
16//!   * [`UintLeast32`](UintLeast32)
17//!   * [`UintLeast64`](UintLeast64)
18//! * [`Int`](Int)
19//!   * [`IntLeast16`](IntLeast16)
20//!   * [`IntLeast32`](IntLeast32)
21//!   * [`IntLeast64`](IntLeast64)
22//! * [`Float`](Float)
23//!   * [`FloatLeast32`](FloatLeast32)
24#![cfg_attr(feature = "f128", doc = "  * [`FloatLeast64`](FloatLeast64)")]
25#![cfg_attr(feature = "std", doc = "  * [`StdFloat`](StdFloat)")]
26//! * [`Array`](array::Array)
27//!
28//! 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`.
29//!
30//! For the sake of compatibility with [`{f16, f32, f64, f128}::to_int_unchecked`](f64::to_int_unchecked), a [`FloatToInt`] trait is also provided.
31//!
32//! Note that all traits provided by this crate are sealed and cannot be implemented by third-party crates (at least currently).
33//!
34//! # Arithmetic types
35//!
36//! MultiType defines different traits for generalising arithmetic types:
37//!
38//! * [`Uint`](Uint) for [`u8`], [`u16`], [`u32`], [`u64`], [`u128`], and [`usize`];
39//! * [`Int`](Int) for [`i8`], [`i16`], [`i32`], [`i64`], [`i128`], and [`isize`];
40//! * [`Float`](Float) for [`f16`], [`f32`], [`f64`], and [`f128`].
41//!
42#![cfg_attr(feature = "std", doc = "Furthermore, `StdFloat` extends the `Float` trait with functionality that is typically only available in `std`'s floating-point types.")]
43//!
44//! ## Sized, arithmetic types
45//!
46//! 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`.
47//!
48//! Additionally, these three arithmetic traits have subtraits that guarantee wider types, for example:
49//!
50//! * `i16` and up implement [`IntLeast16`](IntLeast16);
51//! * `i32` and up implement [`IntLeast32`](IntLeast32);
52//! * Etc.
53//!
54//! Extremely-wide traits, e.g. `IntLeast8` or `IntLeast128`, are considered redundant and are thus not provided.
55//!
56//! # Array types
57//!
58//! MultiType also provides the [`Array`](array::Array) trait for generalising array types -- most often over their length.
59//!
60//! An example of this trait's usecase is actually in this crate:
61//! Take, for instance, the definition of [`Uint`](Uint): It has a `Bytes` associated type that is used by the bytewise constructors and destructors:
62//!
63//! ```rust
64//! pub unsafe trait Uint: /* .. */ {
65//!     type Bytes;
66//!
67//!     fn from_ne_bytes(bytes: Self::Bytes) -> Self;
68//!
69//!     fn to_ne_bytes(self) -> Self::Bytes;
70//!
71//!     // ..
72//! }
73//! ```
74//!
75//! 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.
76//! So, MultiType defines the `Array` trait:
77//!
78//! ```rust
79//! use multitype::Array;
80//!
81//! pub unsafe trait Uint: /* .. */ {
82//!     type Bytes: Array<Scalar = u8>;
83//!
84//!     // ..
85//! }
86//! ```
87//!
88//! With it, it's possible for users to generically use `Uint::to_ne_bytes` as an array type through the trait methods.
89//!
90//! # Examples
91//!
92//! A generic Fibonacci sequence:
93//!
94//! ```rust
95//! use multitype::Uint;
96//!
97//! fn f<T: Uint>(x: T) -> T {
98//!     let mut y    = T::from_u8(0x0);
99//!     let mut y_m1 = T::from_u8(0x0);
100//!     let mut y_m2 = T::from_u8(0x1);
101//!
102//!     let mut i = T::from_u8(0x0);
103//!     while i < x {
104//!         y = y_m1 + y_m2;
105//!
106//!         y_m2 = y_m1;
107//!         y_m1 = y;
108//!
109//!         i += T::from_u8(0x1);
110//!     }
111//!
112//!     y
113//! }
114//!
115//! assert_eq!(f(0u8),   0);
116//! assert_eq!(f(1u8),   1);
117//!
118//! assert_eq!(f(2u16),  1);
119//! assert_eq!(f(3u16),  2);
120//!
121//! assert_eq!(f(4u32),  3);
122//! assert_eq!(f(5u32),  5);
123//!
124//! assert_eq!(f(6u64),  8);
125//! assert_eq!(f(7u64), 13);
126//! ```
127//!
128//! Generic array indexing:
129//!
130//! ```rust
131//! use core::f32;
132//! use multitype::{Array, Float};
133//!
134//! fn complicated_neg<T: Float>(value: T) -> T {
135//!     let mut bytes = value.to_le_bytes();
136//!
137//!     // Invert the sign bit -- which is always the most
138//!     // significant bit of the most significant byte.
139//!     *bytes.as_mut_slice().last_mut().unwrap() ^= 0b10000000;
140//!
141//!     T::from_le_bytes(bytes)
142//! }
143//!
144//! assert_eq!(complicated_neg( 1.0f64), -1.0f64);
145//! assert_eq!(complicated_neg(-1.0f64),  1.0f64);
146//!
147//! assert_eq!(complicated_neg(f32::NEG_INFINITY), f32::INFINITY);
148//! ```
149//!
150//! # Feature flags
151//!
152#![cfg_attr(feature = "alloc",      doc = "* `alloc`: Enables compatibility with [`alloc`] facilities\n")]
153#![cfg_attr(not(feature = "alloc"), doc = "* `alloc`: Enables compatibility with `alloc` facilities\n")]
154#![cfg_attr(feature = "std",        doc = "* `std`: Enables compatibility with [`std`] facilities\n")]
155#![cfg_attr(not(feature = "std"),   doc = "* `std`: Enables compatibility with `std` facilities\n")]
156//!
157//! Unstable features:
158//! * `f16`: Enables support for [`f16`]
159//! * `f128`: Enables support for [`f128`]
160//! * `unstable-docs`: Enables unstable documentation features
161//!
162//! # MSRV policy
163//!
164//! The goal of MultiType is to provide generic traits that bind as much of the standard interfaces as possible.
165//! 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.
166//!
167//! When `const`-compatible traits land, MultiType will implement the feature as quickly as possible.
168//!
169//! # Copyright & Licence.
170//!
171//! Copyright &#169; 2025 Gabriel Bjørnager Jensen.
172//!
173//! 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.
174
175#![no_std]
176
177#![cfg_attr(feature = "f16",           feature(f16))]
178#![cfg_attr(feature = "f128",          feature(f128))]
179#![cfg_attr(feature = "unstable-docs", feature(doc_cfg, intra_doc_pointers))]
180
181extern crate self as multitype;
182
183#[cfg(feature = "alloc")]
184extern crate alloc;
185
186#[cfg(feature = "std")]
187extern crate std;
188
189mod array;
190mod float;
191mod float_to_int;
192mod float_least;
193mod int;
194mod int_least;
195mod std_float;
196mod uint;
197mod uint_least;
198
199pub use array::Array;
200pub use float::Float;
201pub use float_to_int::FloatToInt;
202pub use float_least::FloatLeast32;
203pub use int::Int;
204pub use int_least::{IntLeast16, IntLeast32, IntLeast64};
205pub use uint::Uint;
206pub use uint_least::{UintLeast16, UintLeast32, UintLeast64};
207
208#[cfg(feature = "f128")]
209pub use float_least::FloatLeast64;
210
211#[cfg(feature = "std")]
212pub use std_float::StdFloat;
213
214mod seal {
215	pub trait SealedUint        { }
216	pub trait SealedUintLeast16 { }
217	pub trait SealedUintLeast32 { }
218	pub trait SealedUintLeast64 { }
219
220	pub trait SealedInt        { }
221	pub trait SealedIntLeast16 { }
222	pub trait SealedIntLeast32 { }
223	pub trait SealedIntLeast64 { }
224
225	pub trait SealedFloat        { }
226	pub trait SealedFloatLeast32 { }
227
228	#[expect(clippy::missing_safety_doc)]
229	pub unsafe trait SealedFloatToInt<T> {
230		unsafe fn to_int_unchecked(self) -> T;
231	}
232
233	pub trait SealedArray { }
234
235	#[cfg(feature = "f128")]
236	pub trait SealedFloatLeast64 { }
237
238	#[cfg(feature = "std")]
239	pub trait SealedStdFloat { }
240}
241
242use seal::*;