Search code examples
rustlifetime

rust lifetime error with speedy readable trait


making a message encrypter and decrypter and I am running into some lifetime problems when using speedy to decode the object here is my current code

use flate2::read::ZlibDecoder;
use flate2::write::ZlibEncoder;
use flate2::Compression;
use rsa::{pkcs1::DecodeRsaPublicKey, pkcs8::DecodePrivateKey, Pkcs1v15Encrypt};
use speedy::{LittleEndian, Readable, Writable};
use std::io::Read;

pub struct Communication {
    client_priv_key: rsa::RsaPrivateKey,
    server_pub_key: rsa::RsaPublicKey,
    rng: rand::rngs::ThreadRng,
}

impl Communication {
    pub fn new(priv_key: &str, pub_key: &str) -> Self {
        let client_priv_key = rsa::RsaPrivateKey::from_pkcs8_pem(priv_key).unwrap();
        let server_pub_key = rsa::RsaPublicKey::from_pkcs1_pem(pub_key).unwrap();
        let rng = rand::thread_rng();
        Self {
            client_priv_key,
            server_pub_key,
            rng,
        }
    }

    pub fn encrypt_object<T>(&mut self, obj: &T) -> Vec<u8>
    where
        T: Writable<LittleEndian>,
    {
        let mut buffer = Vec::new();
        obj.write_to_stream(&mut buffer).unwrap();
        let encoder = ZlibEncoder::new(buffer, Compression::default());
        let buffer = encoder.finish().unwrap();
        self.server_pub_key
            .encrypt(&mut self.rng, Pkcs1v15Encrypt, &buffer)
            .unwrap()
    }

    pub fn decrypt_object<'a, T>(&self, buffer: &'a [u8]) -> Result<T, speedy::Error>
    where
        T: Readable<'a, LittleEndian>,
    {
        let decrypted_buffer = self
            .client_priv_key
            .decrypt(Pkcs1v15Encrypt, buffer)
            .map_err(|_| speedy::Error::custom("Decryption failed"))?;

        let mut decoder = ZlibDecoder::new(decrypted_buffer.as_slice());
        let mut decompressed_buffer: Vec<u8> = Vec::new();
        decoder
            .read_to_end(&mut decompressed_buffer)
            .map_err(|_| speedy::Error::custom("Decompression failed"))?;

        T::read_from_buffer(decompressed_buffer.as_slice())
    }
}

cargo check output

    Checking client v0.1.0 (/workspaces/codespaces-blank)
error[E0597]: `decompressed_buffer` does not live long enough
  --> src/lib.rs:54:29
   |
39 |     pub fn decrypt_object<'a, T>(&self, buffer: &'a [u8]) -> Result<T, speedy::Er...
   |                           -- lifetime `'a` defined here
...
49 |         let mut decompressed_buffer: Vec<u8> = Vec::new();
   |             ----------------------- binding `decompressed_buffer` declared here
...
54 |         T::read_from_buffer(decompressed_buffer.as_slice())
   |         --------------------^^^^^^^^^^^^^^^^^^^------------
   |         |                   |
   |         |                   borrowed value does not live long enough
   |         argument requires that `decompressed_buffer` is borrowed for `'a`
55 |     }
   |     - `decompressed_buffer` dropped here while still borrowed

For more information about this error, try `rustc --explain E0597`.
error: could not compile `client` (lib) due to 1 previous error

I tried multiple different lifetime configurations and none of them work and I expect the code to decode the supplied buffer but it just runs into a lifetime error


Solution

  • The issue is that the lifetime 'a is bound to buffer, but you aren't deserializing from buffer but from decompressed_buffer which is a local variable and thus can't satisfy the lifetime that T: Readable<'a, _> expects.

    To fix this, you can use a higher-ranked trait bound to require that T is Readable for any lifetime:

    pub fn decrypt_object<T>(&self, buffer: &[u8]) -> Result<T, speedy::Error>
    where
        T: for<'a> Readable<'a, LittleEndian>,