castingrustparametric-polymorphism

How to cast generic types that I know to be integers?


I want to check return codes of C APIs in a generic way and the result must be free from C types such as libc::c_int. Are there any ways to write a function like

fn check<S: PartialOrd + std::num::Zero, T> (x: S) -> Option<T> {
    if std::num::zero::<S>() <= x { Some(x as T) }
    else { None }
}

when I'm sure that S and T are integral types for all usages of check()? The compiler rejects my code complaining error: non-scalar cast: `S` as `T`


Solution

  • It is impossible to cast arbitrary type to arbitrary type, and that's exactly (almost) what you're trying to do. You need to be more specific in type constraints and conversion operations.

    extern crate num;
    
    use num::{Zero, NumCast};
    
    fn check<S: PartialOrd + Zero + NumCast, T: NumCast>(x: S) -> Option<T> {
        if x >= S::zero() { Some(num::cast(x).unwrap()) }
        else { None }
    }
    
    fn main() {
        let x: i8 = 10;
        let y: Option<i32> = check(x);
        println!("{:?}", y);
        
        let x: i8 = -10;
        let y: Option<i32> = check(x);
        println!("{:?}", y);
    }
    

    Here I'm using a special trait, num::NumCast from num crate, which is implemented for all primitive types and provides a static method which converts to these types from anything which implements num::ToPrimitive. num crate also provides a function, num::cast::cast(), which gives a simple interface to perform numeric casts.

    Note that cast(x) returns Option<T>; it returns None if x can't be represented in the target type. I'm using unwrap() here because in your case, according to your description, inability to convert a value correctly is likely a programming error, so failing the task feels more appropriate. It is also possible to write cast(x) directly:

    if x >= S::zero() { num::cast(x) }
    ...
    

    In this case check() will return None not only when its argument is negative, but also if it is impossible to convert the argument to the result type.