Namespace Subspace :: sus :: num

Safe integer (e.g. i32) and floating point (e.g. f32) numerics, and numeric concepts.

This namespace contains safe integer types and floating point types.

Safe numeric types:

Additionally, there are Concepts that match against safe numerics, C++ primitive types, and operations with numeric types.

The Subspace library numeric types can interoperate with primitive C++ types, but are safer than primitive C++ types and eliminate many classes of bugs that often lead to security vulnerabilities:

  • Integer overflow is not allowed by default (see Overflow behaviour), and will panic to terminate the program. Intentional overflow can be achieved through methods like wrapping_add or saturating_mul. The OverflowInteger type can be used for a series of potentially-overflowing operations and unwraps to an integer value if-and-only-if no overflow has occured.
  • Integers and floats convert implicitly into each other or into primitive types only when no data can be lost, otherwise conversions do not compile. To convert fallibly and observe data loss, use the TryFrom concept methods, such as u32::try_from(3_i32). To do casting conversions with truncation, use Cast.
  • No integer promotion. Math on 8-bit and 16-bit integers will not change their type, unlike primitive types which convert to (signed) int on any math operation.
  • No Undefined Behaviour in conversions. Conversions between all numeric types, and between them and primitive types is well-defined for all possible values, unlike conversions between primitive integer and floating point types which can result in Undefined Behaviour.

The numeric types also come with builtin methods to perform common operations, such as abs, pow, log10, or leading_ones.

Overflow behaviour

The default build configuration will panic on integer overflow in arithmetic operations (+, -, *, /, etc). These checks can be disabled by defining SUS_CHECK_INTEGER_OVERFLOW to false during compilation. Both signed and unsigned integers will then overflow by performing wrapping operations. There is no Undefined Behaviour with signed or unsigned integers unless going through the unchecked operations explicitly, such as unchecked_add.

Division by zero, or overflow in integer division will panic regardless of whether overflow checks are enabled.


To explicitly invoke a lossless conversion, use From. Use Into to constrain inputs in generic code, and sus::into() to type-deduce for conversions. Some lossless conversions are also allowed to happen implicitly, though explicit conversion is better.

To convert and handle the case where data is lost, use TryFrom, or TryInto in generic code. Using T::try_from(U).unwrap() is a quick way to convert and find out if the value was out of range, or to terminate on malicious inputs. Or T::try_from(U).unwrap_or_default() to convert to the input value or else to zero.

To convert with truncation/loss of data, like static_cast, use sus::cast<T>(). It can convert between integers, floats, and enums, for both safe numerics and primitives. See Casting numeric types for the rules of conversion through cast.


  • An integer type that handles overflow instead of panicing.

  • The error type returned when a checked integral type conversion fails.

  • A 32-bit floating point type.

  • A 64-bit floating point type.

  • A 16-bit signed integer.

  • A 32-bit signed integer.

  • A 64-bit signed integer.

  • An 8-bit signed integer.

  • An address-sized signed integer.

  • A 16-bit unsigned integer.

  • A 32-bit unsigned integer.

  • A 64-bit unsigned integer.

  • An 8-bit unsigned integer.

  • A pointer-sized unsigned integer.

  • An address-sized unsigned integer.