casting

Crates.iocasting
lib.rscasting
version0.1.1
created_at2026-01-03 17:56:56.304426+00
updated_at2026-01-03 20:50:01.693567+00
descriptionCastFrom and CastInto traits for generic numeric casting
homepagehttps://github.com/npmccallum/casting
repositoryhttps://github.com/npmccallum/casting
max_upload_size
id2020532
size14,393
Nathaniel McCallum (npmccallum)

documentation

https://docs.rs/casting

README

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.

Commit count: 0

cargo fmt