Crate common_traits

source ·
Expand description

§common_traits

downloads dependents GitHub CI license Latest version Documentation

A collection of traits and dependencies that can be used to write code that is generic over numerical types. It provides also atomic floats implemented using the integer atomic byte 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 implementation of a few primitives such FastRange and SelectInWord.

Everything is experimental and I’ll change them to my needs, respecting semantic versioning. :)

§Example

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 compatability of the vectors
    invariant_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 dependancy chains is the following. Black arcs represent the traits dependancies, the blu 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 missings 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 allows to write generic code (e.g., code mixing a type and its associated atomic type) more easily and with less trait bounds.

§Summary

An highlight of common_traits most noteworthy features.

§Macros

This crate adds the following macros, invariant, invariant_eq, invariant_ne which are similar to the std debug_assert macros, which get checked during debug runs and get replaced with an unreachable_unchecked on release builds.

§Structs

This crate adds emulated atomic floats through fetch_update for the following types:

§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 a Number which 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 2-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:

§Conversion traits

Traits for conversion between types are also provided:

The difference between Castable and To is that Castable does not allow casting from f32 to u32 for example, because Castable 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 enable portable_simd and be able to do generic simd code
  • atomic_from_mut: to add the get_mut_slice and from_mut_slice methods
  • std: to disable for no_std
  • half: to enable support for half::f16 (Experimental)

Macros§

  • An assert macro to check invariants in debug mode and to optimize them away in release mode. This has the same syntax as the std::assert macro.
  • An assert_eq macro to check invariants in debug mode and to optimize them away in release mode. This has the same syntax as the std::assert_eq macro. Look at invariant! for more details.
  • An assert_ne macro to check invariants in debug mode and to optimize them away in release mode. This has the same syntax as the std::assert_ne macro. Look at invariant! for more details.

Structs§

Traits§

  • A trait for types that have a fixed-length representation as a sequence of bytes. This includes all standard numerical scalar types.
  • Values that can be atomically read and written
  • An atomic finite number type.
  • An atomic float type.
  • An atomic integer type.
  • An atomic number type.
  • An atomic signed integer type.
  • An atomic unsigned integer type.
  • Binary selection trait that make it possible to implement traits differently on disjoint types.
  • Trait for primitive integers, 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.
  • CastableInto : CastableFrom = Into : From, It’s easier to use to specify bounds on generic variables
  • A trait to access a type with double the number of bits of Self.
  • Trait for primitive integers, the expected behaviour is to truncate the bits in the UnsignedInt to the possibly smaller UnsignedInt size.
  • DowncastableInto : DowncastableFrom = Into : From, It’s easier to use to specify bounds on generic variables
  • Fast division, modulo reduction, and an alternative operation that maps a number between 0 and n.
  • A number that has a Max and a Min.
  • Common operations on floats
  • Traits for types that can be created safely from an array of bytes.
  • A trait to access a type with half the number of bits of Self.
  • The analog of core::hash::Hash but that uses Hash
  • An generalization of core::hash::Hasher that doesn’t force the output to be u64
  • A trait for operations that are shared by signed and unsigned integers.
  • A trait for types that have an equivalent atomic type.
  • A trait with an associated BooleanSelector type specifying whether the type is atomic. It can be used to implement traits differently for atomic and non-atomic types. See the atomic_data example.
  • A trait with an associated BooleanSelector type specifying whether an type is a float number. It can be used to implement traits differently for float and non float types. See the atomic_data example.
  • A trait with an associated BooleanSelector type specifying whether an type is an Integer number. It can be used to implement traits differently for integer and non integer types. See the atomic_data example.
  • A generic trait with an associated boolean, which can be used to do specialization. See the example atomic_data for more information.
  • A trait with an associated BooleanSelector type specifying whether an integer type is signed. It can be used to implement traits differently for signed and unsigned types. See the atomic_data example.
  • Non zero variants of primitives types for enum optimizations
  • A trait for operations that are shared by integers and floats.
  • A generic Random number generator
  • Implementation of a specific type generation for a Rng
  • An hasher that has extra parameters in initalization
  • Select the i-th 1-bit or 0-bit in a word of memory.
  • A trait for types that can be viewed as a sequence of copiable elements, such as &[T].
  • A trait for types that can be viewed as a growable sequence of copiable elements, such as Vec<T>.
  • A trait for types that can be viewed as a mutable sequence of copiable elements, such as &mut [T].
  • Signed UnsignedInt common operations
  • Take a smaller value and broadcast to all the values
  • Primitive cast between types using as
  • Traits for types that can be cast to an array of bytes.
  • Unsigned UnsignedInt common operations
  • Trait for primitive integers, the expected behaviour for unsigned integers is to zero extend the value, while for signed integers it will sign-extend it to the possibly bigger UnsignedInt size.
  • UpcastableInto : UpcastableFrom = Into : From, It’s easier to use to specify bounds on generic variables