How to allow for truncating casts?


#1

Hello!

I’m currently trying to port my old and trusty pseudo-random number generation code from C to Rust.
It’s just a simple implementation of the Xorshift128+ algorithm, and the algorithm it self was quite easy to implement in rust, but now I’m stuck when trying to implement some “quality of life” functionality for the number generator.

My ambition was to implement a generic function that can generate a random number of any basic type simply by interpreting the resulting u64 as another type, just as i could do in C.
But I can’t find a way to do this, and I’m starting to think that this is not allowed in Rust for safety reasons.

Here’s an example of the closest I have gotten to solving this problem:

Signature of randomization function:

fn xor_shift_128_plus(&mut self) -> u64

generation function:

pub fn generate<T: From<u64>>(&mut self) -> T {
    self.xor_shift_128_plus().into()
}

And this works fine when running the following code:

fn main() {
    let mut prng = Prng::new();
    prng.seed(123);
    println!("{}", prng.generate::<u64>());
}

Output: 16227247910015008063

But if I were to change the call to:

prng.generate::<u32>()

the program wont compile because u32 does not implement From<u64>.

So the problem seems to be that Rust does not allow for casting from a bigger to a smaller type, in respect to bit-size.
Now, I can’t really see why it is problematic to do this operation but I’m sure there are good reasons for not allowing this by default, but surely there must be a way to allow for this type of truncating cast?


#2

I think that “as u32” is a truncating cast, but I’m not sure if you can use it in generic code.


#3

The from/into traits are meant for conversions that are “lossless”, i.e non-truncating. One way to solve this would be to define a truncate or similar trait and implement it for the types you intend to use, where the implementation uses as to do a truncating cast into the type you want.

Maybe there should be a truncating into in the standard library for use with generic functions.


#4

As a non-std alternative, you may want to look into the “conv” crate, which features many kinds of lossy conversions including truncation : https://docs.rs/conv/0.3.3/conv/ .