Crate casting

Crate casting 

Source
Expand description

§casting

CI Crates.io Documentation License: MIT

Generic numeric casting traits mirroring From/Into.

casting provides CastFrom and CastInto traits that mirror the standard library’s From and Into, but with casting semantics. This enables:

  • Generic programming over type conversions (impossible with as)
  • Extending cast behavior to custom types (newtypes, wrappers)
  • Uniform APIs that work consistently across numeric types

§Relationship to From/Into

CastFrom and CastInto mirror the standard library’s From and Into traits, but with casting semantics:

  • From/Into: Lossless, infallible conversions (e.g., u8u16)
  • CastFrom/CastInto: Casting conversions that may lose precision or wrap (e.g., f64i32, u16u8)

Like the standard library:

  • CastInto is automatically implemented for all types that implement CastFrom
  • You should implement CastFrom rather than CastInto directly
  • The blanket implementation ensures consistency and reduces boilerplate

§Installation

[dependencies]
casting = "0.1"

For nightly features (f16 and f128 support):

[dependencies]
casting = { version = "0.1", features = ["nightly"] }

§Quick Start

use casting::{CastFrom, CastInto};

// Basic usage with CastInto
let x: u8 = 255;
let y: u16 = x.cast_into();
assert_eq!(y, 255u16);

// Or with CastFrom
let z = u16::cast_from(x);
assert_eq!(z, 255u16);

// Generic programming
fn convert_slice<T, U>(input: &[T]) -> Vec<U>
where
    T: CastInto<U> + Copy,
{
    input.iter().map(|&x| x.cast_into()).collect()
}

let bytes: Vec<u8> = vec![1, 2, 3];
let ints: Vec<i32> = convert_slice(&bytes);
assert_eq!(ints, vec![1i32, 2, 3]);

// Extensibility to custom types
#[derive(Copy, Clone)]
struct Kilometers(f32);

impl CastFrom<Kilometers> for f64 {
    fn cast_from(value: Kilometers) -> f64 {
        (value.0 * 1000.0) as f64 // Convert to meters
    }
}

let distance = Kilometers(5.5);
let meters: f64 = distance.cast_into();
assert_eq!(meters, 5500.0);

§Supported Types

  • Boolean: bool (casts to integers only)
  • Character: char (casts to integers only, cast from u8 only)
  • Integers: u8, u16, u32, u64, u128, usize, i8, i16, i32, i64, i128, isize
  • Floats: f32, f64, and f16/f128 with the nightly feature

All integer and float types can cast between each other. bool and char have limited casting support as noted above.

§Features

  • Zero overhead: Compiles to the same code as as casts
  • Type-safe: Return types are inferred from context
  • no_std: Works in embedded and bare-metal environments
  • Extensible: Add casting to your own types

§Cargo Features

  • nightly: Enables f16 and f128 support (requires nightly Rust)

§Use Cases

  • Generic code that converts between numeric types
  • Libraries with flexible numeric type conversions
  • Custom numeric types (newtypes, wrappers) that need casting
  • no_std environments requiring portable conversions

§Why Not Just Use as?

The as operator can’t be used in generic contexts:

Generic programming:

use casting::CastInto;

fn double_and_convert<T, U>(x: T) -> U
where
    T: CastInto<U> + std::ops::Add<Output = T> + Copy,
{
    (x + x).cast_into()
}

Custom type extensibility:

use casting::{CastFrom, CastInto};

#[derive(Copy, Clone)]
struct Degrees(f32);

impl CastFrom<Degrees> for f64 {
    fn cast_from(value: Degrees) -> f64 {
        value.0 as f64
    }
}

Neither is possible with the built-in as operator.

§License

Licensed under the MIT License.

Traits§

CastFrom
Cast from one type to another.
CastInto
Cast into another type.