'Unable to use concat on vec<u8> in my function

I have a program where I need to append two Vec<u8> before they are are serialized.

Just to be sure how to do it, I made this example program:

let a: Vec<u8> = vec![1, 2, 3, 4, 5, 6];
let b: Vec<u8> = vec![7, 8, 9];
let c = [a, b].concat();
println!("{:?}", c);

Which works perfectly. The issue is now when I have to implement it in my own project. Here I need to write a function, the function takes a struct as input that looks like this:

pub struct Message2 {
    pub ephemeral_key_r: Vec<u8>,
    pub c_r: Vec<u8>,
    pub ciphertext2: Vec<u8>,
}

and the serialalization function looks like this:

pub fn serialize_message_2(msg: &Message2) -> Result<Vec<u8>> {
    let c_r_and_ciphertext = [msg.c_r, msg.ciphertext2].concat();
    let encoded = (
        Bytes::new(&msg.ephemeral_key_r),
        Bytes::new(&c_r_and_ciphertext),
    );
    Ok(cbor::encode_sequence(encoded)?)
}

The first issue that arises here is that it complains that msg.ciphertext2 and msg.c_r are moved values. This makes sense, so I add an & in front of both of them.

However, when I do this, the call to concat() fails, with this type error:

util.rs(77, 59): method cannot be called on `[&std::vec::Vec<u8>; 2]` due to unsatisfied trait bounds

So, when I borrow the values, then the expression [&msg.c_r, &msg.ciphertext2] becomes an array of two vec's, which there is not a concat() defined for.

I also tried calling clone on both vectors:

let c_r_and_ciphertext = [msg.c_r.clone(), msg.ciphertext2.clone()].concat();

and this actually works out!

But now I'm just wondering, why does borrowing the values change the types? and is there any things to think about when slapping on clone to values that are moved, and where I cannot borrow for some reason?



Solution 1:[1]

I tried to reproduce your error message, which this code does:

fn main() {
    let a = vec![1, 2];
    let b = vec![3, 4];
    println!("{:?}", [&a, &b].concat())
}

gives:

error[E0599]: the method `concat` exists for array `[&Vec<{integer}>; 2]`, but its trait bounds were not satisfied
 --> src/main.rs:4:31
  |
4 |     println!("{:?}", [&a, &b].concat())
  |                               ^^^^^^ method cannot be called on `[&Vec<{integer}>; 2]` due to unsatisfied trait bounds
  |
  = note: the following trait bounds were not satisfied:
          `[&Vec<{integer}>]: Concat<_>`

It is a simple matter of helping the compiler to see that &a works perfectly fine as a slice, by calling it &a[..]:

fn main() {
    let a = vec![1, 2];
    let b = vec![3, 4];
    println!("{:?}", [&a[..], &b[..]].concat())
}

why does borrowing the values change the types?

Borrowing changes a type into a reference to that same type, so T to &T. These types are related, but are not the same.

is there any things to think about when slapping on clone to values that are moved, and where I cannot borrow for some reason?

Cloning is a good way to sacrifice performance to make the borrow checker happy. It (usually) involves copying the entire memory that is cloned, but if your code is not performance critical (which most code is not), then it may still be a good trade-off...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 hkBst