Home > Mobile >  Rust beginner question, trait with generics and secure the conversion from vector to array at compil
Rust beginner question, trait with generics and secure the conversion from vector to array at compil

Time:07-25

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 information N at compile time
  • Removed the BYTES constant
  • Replaced the length check with a success check of try_into()

And I replaced some erroneous consts with let.

  • Related