Having trouble defining a generic type function

Greetings,

I am trying to write a function that works for multi-byte number, e.g. u16, u32,...

The code looks like this, but currently it has several errors, what can I do to suppress the error and make it work?

I'm new to rust, any suggestions are appreciated.

fn read_mbytes_num<T>(raw_data: &[u8], pos: &mut usize) -> T 
{
    const type_size: usize = std::mem::size_of::<T>();   //<--error here
    if *pos + type_size <= raw_data.len() {
        let mut tmp = [0u8; type_size];
        tmp.copy_from_slice(&raw_data[*pos..*pos+type_size]);
        *pos += type_size;
        T::from_le_bytes(tmp)       //<--error here
    } else {
        0
    }
}

Rust's generics don't behave like C++ templates or macros. They're statically and strongly-typed, and you must declare traits for every single operation you use on a generic type.

If you use generics with just a T type, the compiler is pretty serious about the abstraction being for any type imaginable, and requires the function to work with strings, arrays, closures, file handles, zero-length unit types, and literally any type in existence.

Even if the type actually has the methods you use, the compiler will intentionally hide them, and won't let you use them if these methods aren't part of a trait declared explicitly in the generic function's signature.

Unfortunately, there's no trait for numeric types in the standard library. Usually people use num-traits to work with numeric types generically. However, I don't see from_le_bytes there either, so you will have to invent and implement your own trait for it.

Alternatively, use a macro to define such function for each type you want.

I understand why T::from_le_bytes(tmp) line fails. Is const type_size: usize = std::mem::size_of::<T>(); line failing because of const? Changing it to let would work?

Thanks for the explanation.

Understood. Guess this code might work only if Rust supports limiting generic type T to certain types in the future. I'll just copy-paste this functions for several types for now...

Cannot change const to let, because we need this constant for array initialization.

1st error:

can't use generic parameters from outer function
use of generic parameter from outer function rustc E0401

2nd error:

no function or associated item named `from_le_bytes` found for type parameter `T` in the current scope
function or associated item not found in `T` rustc E0599

That const thing is an awful language wart ;(

const for values is older than Rust's support for compile-time evaluation. This syntax isn't a compile-time let, but rather as something closer to being a global definition:

const read_mbytes_num__type_size: usize = std::mem::size_of::<T>(); 

fn read_mbytes_num<T>(raw_data: &[u8], pos: &mut usize) -> T 
{
  …this const isn't actually defined here…
}

so Rust doesn't know what to do with that "unrelated" T there.

If you spam the code with literal std::mem::size_of::<T>() instead of type_size, it gets you further, but you still run into limitation of compile-time-sized arrays. This is under-developed area of Rust, and const generics are still full of holes.

Use a macro. Rust's macros work like C++ templates that let you use any syntax that compiles, and you can use any numeric type, with any of its methods, and normal let bindings, and don't have to declare traits or consts.

2 Likes