Reputation: 23
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:
BitVec
and BitSlice
u32
or u64
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!
Upvotes: 2
Views: 361
Reputation: 42756
You can create a simple macro to declare them:
use bitvec::prelude::*; // bitvec = "0.22.3"
macro_rules! bitvec_to {
($func_name:ident, $input_type:ty, $output_type:ty) => {
fn $func_name(bv: &$input_type) -> $output_type {
let mut int = 0;
for bit in bv {
int = int << 1;
if bit == true {
int += 1;
}
}
return int;
}
};
}
bitvec_to!(bslice_to_int, BitSlice::<Lsb0, u8>, u32);
bitvec_to!(bv_to_int, BitVec::<Lsb0, u8>, u64);
Upvotes: 1