Expand description
§common_traits
A collection of traits and types that can be used to write code
that is generic over numerical types. It also provides atomic floats
implemented using the integer atomic type with the same number of
bits, and support for half-precision floats via the crate half.
Additionally, there are a few traits missing from the standard
library, such as Sequence, variants of existing library traits
such as Rng and Hash, and macros like invariant.
Finally, we provide traits for casting between types, such as
UpcastableInto, and fast implementations of a few primitives
such as FastRange and SelectInWord.
Everything is experimental and I’ll change them to my needs, respecting semantic versioning. :)
§Examples
Mixed precision generic dot products!
use common_traits::*;
#[inline]
pub fn dot_product<MT: Number, RT: Number, A, B>(a: A, b: B) -> RT
where
A: Sequence,
B: Sequence,
A::Item: To<MT>,
B::Item: To<MT>,
MT: To<RT>,
RT: To<MT>,
{
// Ensure compatibility of the vectors
assert_eq!(a.len(), b.len());
// Compute the dot product
let mut accum = RT::ZERO;
for (a, b) in a.iter().zip(b.iter()) {
accum = (a.to()).mul_add(b.to(), accum.to()).to();
}
accum
}
let x: Vec<f32> = vec![1.0, 2.0, 3.0];
let w: Vec<u8> = vec![3, 2, 1];
// compute the dot product between f32 and u8, casting to f64 and
// accumulating as u16
let res: u16 = dot_product::<f64, _, _, _>(&x, &w);
println!("{:?}", res);§Numerical traits at a glance
The numerical traits dependency chain is the following. Black arcs represent the trait dependencies, the blue arcs represent the possibility to access an associated type implementing that trait.
§Why?
The point of making this crate public is to be able to discuss this as it covers many core missing features from Rust.
The traits in this crate are similar to the ones from num-traits
but they are more interconnected (the blue arcs in the previous
graph), which makes it possible to write generic code (e.g., code
mixing a type and its associated atomic type) more easily and with
less trait bounds.
§Summary
A highlight of common_traits’ most noteworthy features.
§Macros
This crate adds the following macros: invariant,
invariant_eq, invariant_ne, which are similar to the
debug_assert macros, which get checked during debug runs and get
replaced with core::hint::unreachable_unchecked on release builds.
§Structs
This crate adds emulated atomic floats implemented via
fetch_update for the following types:
f64asAtomicF64f32asAtomicF32half::f16asAtomicF16half::bf16asAtomicBF16
§Numerical Traits
This crate provides the following traits for numerical types:
Number: something that can be added, subtracted, multiplied, divided and has a zero and a one.FiniteRangeNumber: aNumberwhich has a minimum and a maximum.Float: float numbers.Integer: an integer number represented as a sequence of bits.SignedInt: a signed integer represented in two’s complement.UnsignedInt: an unsigned integer.
§Atomic Numerical Traits
There are two main traits for working with atomic values:
Atomic: for values that can be read and written atomically.IntoAtomic: for values that can be converted into atomic types.
Each numerical trait has an atomic equivalent:
§Miscellaneous Traits
The crate also contains a couple of extra traits:
Sequence,SequenceMut, andSequenceGrowableto abstract over slices and other sequence-like types.AsBytes,ToBytes, andFromBytesare traits used to convert types to and from byte arrays.NonZero, a version ofSelfthat cannot be zero;UnsignedIntandSignedInthave an associated type implementing this.FastRangefor faster div, mod, and range operations.SelectInWordto find the position of the i-th 1 or 0 in words of memory.Splatto broadcast a smaller type on a larger type, mainly used for SWAR.Rngfor a generic random number generator.SameAs, an unsafe marker trait guaranteeing that a type and its atomic variant have the same memory layout.Hasher, that is likestd::hash::Hasherbut allows returning a generic type instead of au64.SeedableHasher, a standard way to initialize hashers.
§Conversion Traits
Traits for conversion between types are also provided:
To, to cast primitive values usingas.DoubleTypeandHalfTypecan be used to access bigger or smaller types in a generic way.UpcastableIntoandUpcastableFromto cast primitive values which cannot lose precision.
DowncastableIntoandDowncastableFromto cast primitive values which can lose precision.
CastableIntoandCastableFromto cast primitive values which may or may not lose precision. This is the union ofDowncastableIntoandUpcastableInto.
The difference between CastableInto and To is that
CastableInto does not allow casting from f32 to u32 for
example, because CastableInto is implemented only between
integers and between floats, while To is implemented for all
primitive types.
§Features
This crate has the following features:
simd: to enableportable_simdand be able to do generic SIMD codestd: to enable standard library supportalloc: to enable allocator support forVec/Boxwithout fullstdhalf: to enable support forhalf::f16(experimental)nightly_f16: to enable support for the nativef16type. Requires a nightly compiler and is mutually exclusive withhalf.
Macros§
- invariant
- An
unsafeassert macro that checks an invariant in debug mode and optimizes it away in release mode. It has the same syntax asassert!. - invariant_
eq - An
assert_eq!macro to check invariants in debug mode and to optimize them away in release mode. This has the same syntax as theassert_eq!macro. Seeinvariant!for more details. - invariant_
ne - An
assert_ne!macro to check invariants in debug mode and to optimize them away in release mode. This has the same syntax as theassert_ne!macro. Seeinvariant!for more details.
Structs§
- AtomicB
F16 - Atomic
half::bf16based onAtomicU16. - Atomic
F16 - Atomic
half::f16based onAtomicU16. - Atomic
F32 - Atomic
f32based onAtomicU32. - Atomic
F64 - Atomic
f64based onAtomicU64. - False
BooleanSelectorversion offalse, this is an empty struct used only for type system bounds.- True
BooleanSelectorversion oftrue, this is an empty struct used only for type system bounds.
Traits§
- AsBytes
- A trait for types that have a fixed-length representation as a sequence of bytes. This includes all standard numerical scalar types.
- Atomic
- Values that can be atomically read and written.
- Atomic
Finite Range Number - An atomic finite number type.
- Atomic
Float - An atomic float type.
- Atomic
Integer - An atomic integer type.
- Atomic
Number - An atomic number type.
- Atomic
Signed Int - An atomic signed integer type.
- Atomic
Unsigned Int - An atomic unsigned integer type.
- Boolean
Selector - Binary selection trait that makes it possible to implement traits differently on disjoint types.
- Castable
From - Trait for primitive numeric types; this is the combination of
[
DowncastableFrom] and [UpcastableFrom]. Prefer using the other two traits, as casting without knowing which value will be bigger might result in hard-to-find bugs. - Castable
Into CastableInto:CastableFrom=Into:From. It’s easier to use to specify bounds on generic variables.- Double
Type - A trait to access a type with double the number of bits of
Self. - Downcastable
From - Trait for primitive numeric types; the expected behavior for integers is to truncate the bits to the possibly smaller size, and for floats it will narrow to the target precision.
- Downcastable
Into DowncastableInto:DowncastableFrom=Into:From. It’s easier to use to specify bounds on generic variables.- Fast
Range - Fast division, modulo reduction, and an alternative operation
that maps a number between 0 and
d. - Finite
Range Number - A number that has a
MINand aMAX. - Float
- Common operations on floats.
- From
Bytes - Trait for types that can be created safely from an array of bytes.
- Half
Type - A trait to access a type with half the number of bits of
Self. - Hash
- Analog of
core::hash::Hash, usingHasher. - Hasher
- A generalization of
core::hash::Hasherthat doesn’t force the output to beu64. - Integer
- A trait for operations that are shared by signed and unsigned integers.
- Into
Atomic - A trait for types that have an equivalent atomic type.
- IsAtomic
- A trait with an associated
BooleanSelectortype specifying whether the type is atomic. It can be used to implement traits differently for atomic and non-atomic types. See theatomic_dataexample. - IsFloat
- A trait with an associated
BooleanSelectortype specifying whether a type is a float number. It can be used to implement traits differently for float and non-float types. See theatomic_dataexample. - IsInteger
- A trait with an associated
BooleanSelectortype specifying whether a type is an integer number. It can be used to implement traits differently for integer and non-integer types. See theatomic_dataexample. - IsNon
Zero - A generic trait with an associated boolean, which can be used to do
specialization. See the example
atomic_datafor more information. - IsSigned
- A trait with an associated
BooleanSelectortype specifying whether an integer type is signed. It can be used to implement traits differently for signed and unsigned types. See theatomic_dataexample. - NonZero
- Non-zero variants of primitive types for enum optimizations.
- Number
- A trait for operations that are shared by integers and floats.
- Rng
- A generic random number generator.
- RngNext
- Implementation of a specific type generation for an
Rng. - SameAs
- Unsafe marker trait for types whose atomic version has the same size and bit representation.
- Seedable
Hasher - A hasher with additional initialization parameters.
- Select
InWord - Selects the
rank-th 1-bit or 0-bit in a word of memory. - Sequence
- A trait for types that can be viewed as a sequence of copyable elements,
such as
&[T]. - Sequence
Growable - A trait for types that can be viewed as a growable sequence of copyable elements,
such as
Vec<T>. - Sequence
Mut - A trait for types that can be viewed as a mutable sequence of copyable elements,
such as
&mut [T]. - Signed
Int - Signed integer common operations.
- Splat
- Takes a smaller value and broadcasts it to all positions.
- To
- Casts a primitive value to another type using
as. - ToBytes
- Trait for types that can be cast to an array of bytes.
- Unsigned
Int - Unsigned integer common operations.
- Upcastable
From - Trait for primitive numeric types; the expected behavior for unsigned integers is to zero-extend the value, for signed integers it will sign-extend it to the possibly bigger size, and for floats it will widen to the target precision.
- Upcastable
Into UpcastableInto:UpcastableFrom=Into:From. It’s easier to use to specify bounds on generic variables.