Home > Software design >  Rust Generics - cannot infer type for type parameter `T`
Rust Generics - cannot infer type for type parameter `T`

Time:06-05

I have some Rust FFI code that I would like to apply to i32, i64, f32, f64 and so on. So using a generic type T would help me to avoid repeating large blocks of code.

In this example, I have cut out i64 and pasted in T (and decorated the fn names with <T>). The i64 version works fine.

pub struct SeriesC {
    se: Series,
}

impl SeriesC {
    fn new<T>(name: String, data: Vec::<T>) -> SeriesC {
        SeriesC {
            se: Series::new(&name, data),
        }   
    }
}

#[no_mangle]
pub extern "C" fn se_new(
    string: *const c_char,
    data: *const *const i64,
    len: size_t, 
) -> *mut SeriesC {

    let se_name = unsafe {
        CStr::from_ptr(string).to_string_lossy().into_owned()
    };  

    let mut se_data: Vec<i64> = Vec::<i64>::new();
    unsafe {
        assert!(!data.is_null());

        for item in slice::from_raw_parts(data, len as usize) {
            se_data.push(*item as i64);
        };  
    };  

    Box::into_raw(Box::new(SeriesC::new(se_name, se_data)))
}

It seems that whatever I try gives me errors. I have also considered Arrays instead of Vecs, but I am pretty sure I want Vecs as the length is not known at compile time. This attempt says:

error[E0277]: the trait bound `polars::prelude::Series: polars::prelude::NamedFrom<Vec<T>, _>` is not satisfied
  --> src/lib.rs:20:17
   |
20 |             se: Series::new(&name, data),
   |                 ^^^^^^^^^^^ the trait `polars::prelude::NamedFrom<Vec<T>, _>` is not implemented for `polars::prelude::Series`
   |
   = help: the following implementations were found:
             <polars::prelude::Series as polars::prelude::NamedFrom<&polars::prelude::Series, str>>
             <polars::prelude::Series as polars::prelude::NamedFrom<T, ListType>>
             <polars::prelude::Series as polars::prelude::NamedFrom<T, T>>
             <polars::prelude::Series as polars::prelude::NamedFrom<T, [&'a str]>>
           and 33 others

Any advice gratefully received!

CodePudding user response:

When the compiler knows that the type is i64, it can see that Series implements the required NamedFrom conversion trait due to the implementation impl<T> NamedFrom<T, [i64]> for Series where T: AsRef<[i64]> provided by the polars library. There isn't an implementation for NamedFrom when T is totally unbounded -- there are types you could substitute for T for which there would be no implementation of NamedFrom.

To make this work generically, you need to add a suitable bound so that the compiler knows that there is a NamedFrom<Vec<T>, [T]> implementation on Series, which will appropriately restrict usage of your SeriesC::new() function to types T for which such as implementation exists.

fn new<T>(name: String, data: Vec::<T>) -> SeriesC
    where Series: NamedFrom<Vec<T>, [T]>
{ ... }
  • Related