Here I have two functions in rust which convert a bitvec into an integer. They are identical except for their types, so I'd like to template over both:
- the input types
BitVecandBitSlice - the return type
u32oru64
use bitvec::prelude::*; // bitvec = "0.22.3" fn bslice_to_int(bv: &BitSlice::<Lsb0, u8>) -> u32 { let mut int = 0; for bit in bv { int = int << 1; if bit == true { int += 1; } } return int; } fn bv_to_int(bv: &BitVec::<Lsb0, u8>) -> u64 { let mut int = 0; for bit in bv { int = int << 1; if bit == true { int += 1; } } return int; } fn main() { let bits = bitvec![Lsb0, u8; 1,0,1,0]; let val1 = bslice_to_int(&bits[0..2]); let val2 = bv_to_int(&bits); println!("{} {}", val1, val2); // "10 2" } I seem to have a different problem with each.
Trying 1) to make the input type generic:
fn bv_to_int_generic_in<T>(bv: &T) -> u64 { let mut int = 0; for bit in bv { int = int << 1; if bit == true { int += 1; } } return int; } fn main() { let bits = bitvec![Lsb0, u8; 1,0,1,0]; let val1 = bv_to_int_generic_in::<BitSlice::<Lsb0, u8>>(&bits[0..2]); let val2 = bv_to_int_generic_in::<BitVec::<Lsb0, u8>>(&bits); println!("{} {}", val1, val2); } doesn't compile, and gives an error that the generic T doesn't have the Iterator trait implemented:
error[E0277]: `&T` is not an iterator --> src/main.rs:28:14 | 28 | for bit in bv { | ^^ `&T` is not an iterator | = help: the trait `Iterator` is not implemented for `&T` = note: required because of the requirements on the impl of `IntoIterator` for `&T` note: required by `into_iter` --> /Users/jlees/.rustup/toolchains/stable-x86_64-apple-darwin/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:234:5 | 234 | fn into_iter(self) -> Self::IntoIter; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Trying 2) to make the return type generic:
// Trying to template the output type fn bv_to_int_generic_out<T>(bv: &BitVec::<Lsb0, u8>) -> T { let mut int: T = 0; for bit in bv { int = int << 1; if bit == true { int += 1; } } return int; } fn main() { let bits = bitvec![Lsb0, u8; 1,0,1,0]; let val1: u32 = bv_to_int_generic_out::<u32>(&bits); let val2: u64 = bv_to_int_generic_out::<u64>(&bits); println!("{} {}", val1, val2); } also doesn't compile, and gives errors that T is not an {integer}:
error[E0308]: mismatched types --> src/main.rs:55:20 | 54 | fn bv_to_int_generic_out<T>(bv: &BitVec::<Lsb0, u8>) -> T { | - this type parameter 55 | let mut int: T = 0; | - ^ expected type parameter `T`, found integer | | | expected due to this | = note: expected type parameter `T` found type `{integer}` error[E0369]: no implementation for `T << {integer}` --> src/main.rs:57:15 | 57 | int = int << 1; | --- ^^ - {integer} | | | T | help: consider restricting type parameter `T` | 54 | fn bv_to_int_generic_out<T: std::ops::Shl<Output = {integer}>>(bv: &BitVec::<Lsb0, u8>) -> T { | +++++++++++++++++++++++++++++++++++ error[E0368]: binary assignment operation `+=` cannot be applied to type `T` --> src/main.rs:59:7 | 59 | int += 1; | ---^^^^^ | | | cannot use `+=` on type `T` | help: consider restricting type parameter `T` | 54 | fn bv_to_int_generic_out<T: std::ops::AddAssign>(bv: &BitVec::<Lsb0, u8>) -> T { | +++++++++++++++++++++ See also this gist for the above code in one place: https://gist.github.com/johnlees/49e6a7bd85b3545bba20e8670180f24a
I am new to rust, and I realise that I'm trying to write these like C++ templates which may well be the wrong approach. Any advice on the correct rust approach for making either the input or output types generic would be appreciated!