0

I have a simple struct that defines some kind of message to be sent over network.

struct Message {
    message_type: u32,
    user_id: u32,
    message: Vec<u8>,
}

And somewhere else I want to serialize it into a simple sequence of bytes. So I defined iterator for the bytes of the message like this:

impl Message {
    fn iter(&self) -> std::iter::Chain<std::iter::Chain<std::slice::Iter<'_, u8>, std::slice::Iter<'_, u8>>, std::slice::Iter<'_, u8>> {
        self.message_type
            .to_be_bytes()
            .iter()
            .chain(self.user_id.to_be_bytes().iter())
            .chain(self.message.iter())
    }

    fn data(&self) -> Vec<u8> {
        self.iter().cloned().collect()
    }
}

Yes, the type keeps growing with more chained iterators, which is kind of a shame

But I get 2 compiler errors when I try to run it

cannot return value referencing temporary value

returns a value referencing data owned by the current function. rustc(E0515)

Guess I'm not versed enough in the rust's ownership system

Link0
  • 655
  • 5
  • 17
  • tips: you can write `impl Iterator` as return type. (maybe not for your case but remember this as a shortcut) – Stargateur May 17 '20 at 18:54
  • Could be a solution: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=57c72d9b15777cd0c6e57e592b933430 – Stargateur May 17 '20 at 19:15

1 Answers1

1

The problem why rust borrow checker is complaining is because to_be_bytes() functions return an array which is stored on stack. The code is attempting to create a iterator to a object that is allocated on stack and this iterator is outliving the object.

self.message_type.to_be_bytes()

For example:
This creates an array on stack and .iter() is only valid as long as this object exists.

There are couple of ways fix this. Make the iter and eventual conversion to bytes all in the same function.

fn data(&self) -> Vec<u8> {
    self.message_type
        .to_be_bytes()
        .iter()
        .chain(self.user_id.to_be_bytes().iter())
        .chain(self.message.iter()).map(|x| *x).collect()
}

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=129af6e7da3d1e3a9454fffbb124e170

Caution: Whenever you convert to bytes, confirm whether you want little endian/big endian and all the bytes follow the same endianess.

apatniv
  • 1,771
  • 10
  • 13
  • "The problem why rust borrow checker is complaining is because to_be_bytes() functions return an array which is stored on stack." that haft false, stack or not that not why rust is complaining. You should not think to the stack in a language like rust. The answer is more because no one own the array so it would be invalid to have a reference to it. – Stargateur May 17 '20 at 18:57