How can I map a value to a type in Rust?

Viewed 475

I am writing a program which accepts a numerical type on the command line, and then calls a generic function using that type. For example, I run program thus:

my_programme u32

...and in my code I have:

match cli_type
{
   "u32" =>
   {
       my_generic_function::<u32>(args);
   },
   "u16" =>
   ...

If I want to do this for 8, 16, 32, and 64 bit integers, both signed and unsigned, that's a lot of calls to my_generic_function(). It looks messy and seems needless.

Can I define a map between &str or String values and type T, or write a function to return type T, so instead of the match statement, I could just write:

my_generic_function::<get_type(cli_type)>(args);
1 Answers

Rust doesn't keep any type information at runtime. There is a function in the standard library, std::any::type_name, which can give you the name of a type, but it's just a string and there is no way to get back into the world of types. That all happens at compile time and can't be changed later.

However, you can save some code with a macro:

macro_rules! make_call_typed {
   ($($t: ty),*) => {
       fn call_typed(input: &str, args: &str) {
           match input {
               $(
                   stringify!($t) => {
                       my_generic_function::<$t>(args);
                   }
               ),*
               other => panic!("unexpected type: {}", other)
           }
        }
    }
}

When you call it like this:

make_call_typed!(u32, u16, i32, i16);

It will generate code like this:

fn call_typed(input: &str, args: &str) {
    match input {
        "u32" => {
            my_generic_function::<u32>(args);
        }
        "u16" => {
            my_generic_function::<u16>(args);
        }
        "i32" => {
            my_generic_function::<i32>(args);
        }
        "i16" => {
            my_generic_function::<i16>(args);
        }
        other => panic!("unexpected type: {}", other),
    }
}
Related