I wonder if it is possible to implement this Unsigned
trait that allows performing conversions from bytes arrays to this Unsigned
type (like a constructor). The add
function should work particularly for u32
and u64
. For achieving it I was thinking in doing something like this:
pub enum Error {
BadLength,
}
trait Unsigned {
type Array;
const BYTES: usize;
fn from_le_bytes(bytes: Self::Array) -> Self;
}
impl Unsigned for u32 {
type Array = [u8; 4];
const BYTES: usize = 4;
fn from_le_bytes(bytes: Self::Array) -> Self {
u32::from_le_bytes(bytes)
}
}
fn add<W>(a: Vec<u8>, b: Vec<u8>) -> Result<W, Error>
where W: Unsigned std::ops::Add<Output = W>
{
if a.len() != W::BYTES || b.len() != W::BYTES {
return Err(Error::BadLength)
}
const c: W = W::from_le_bytes(a[0..W::BYTES]);
const d: W = W::from_le_bytes(b[0..W::BYTES]);
Ok(c d)
}
fn main() {
const a: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
const b: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
if let Ok(c) = add::<u32>(a, b) {
println!("{}", c);
}
}
Currently, the compiler is telling me:
Compiling from_le_bytes v0.1.0 (/home/guido/codes/from_le_bytes)
error[E0308]: mismatched types
--> src/main.rs:28:33
|
28 | let c: W = W::from_le_bytes(a[0..W::BYTES]);
| ^^^^^^^^^^^^^^ expected associated type, found slice `[u8]`
|
= note: expected associated type `<W as Unsigned>::Array`
found slice `[u8]`
help: consider constraining the associated type `<W as Unsigned>::Array` to `[u8]`
|
23 | where W: Unsigned<Array = [u8]> std::ops::Add<Output = W>
|
error[E0308]: mismatched types
--> src/main.rs:29:33
|
29 | let d: W = W::from_le_bytes(b[0..W::BYTES]);
| ^^^^^^^^^^^^^^ expected associated type, found slice `[u8]`
|
= note: expected associated type `<W as Unsigned>::Array`
found slice `[u8]`
help: consider constraining the associated type `<W as Unsigned>::Array` to `[u8]`
|
23 | where W: Unsigned<Array = [u8]> std::ops::Add<Output = W>
|
For more information about this error, try `rustc --explain E0308`.
error: could not compile `from_le_bytes` due to 2 previous errors
Is there any way to compile the code, transform those vectors into u32 and do the addition?
CodePudding user response:
Something like this?
pub enum Error {
BadLength,
}
trait Unsigned {
type Array;
fn from_le_bytes(bytes: Self::Array) -> Self;
}
impl Unsigned for u32 {
type Array = [u8; 4];
fn from_le_bytes(bytes: Self::Array) -> Self {
u32::from_le_bytes(bytes)
}
}
fn add<W>(a: Vec<u8>, b: Vec<u8>) -> Result<W, Error>
where
W: Unsigned std::ops::Add<Output = W>,
Vec<u8>: TryInto<W::Array>,
{
let a: W::Array = a.try_into().map_err(|_| Error::BadLength)?;
let b: W::Array = b.try_into().map_err(|_| Error::BadLength)?;
let c = W::from_le_bytes(a);
let d = W::from_le_bytes(b);
Ok(c d)
}
fn main() {
let a: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
let b: Vec<u8> = vec![0x01, 0x02, 0x03, 0x04];
if let Ok(c) = add::<u32>(a, b) {
println!("{}", c);
}
}
134611970
Explanation
I noticed that the TryInto
is implemented for Vec<u8>
and [u8; N]
:
impl<T, A, const N: usize> TryFrom<Vec<T, A>> for [T; N]
This means if we have the full type, including N
, we don't need the BYTES
constant.
Further, we can use whether or not the try_into
worked or failed to determine if the length was correct.
So therefore, I:
- Changed the type
Array
to carry the length informationN
at compile time - Removed the
BYTES
constant - Replaced the length check with a success check of
try_into()
And I replaced some erroneous const
s with let
.