Sergio Ivanuzzo
Sergio Ivanuzzo

Reputation: 1922

Not clear how to correctly define lifetime for struct

I have TCP Client, which process some handlers. I need to share data between them, so I implemented Session struct for this case:

struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
       }
    }
}

I added access by reference to allow data be borrowed. But, when I try to use this struct inside my code, I got errors related to lifetime:

implicit elided lifetime not allowed here

or

cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

This is minimal sandbox implementation.

Just in case this is my sample code (mostly it's similar to my real app):

// data which store values that I need to share between handlers
struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
        }
    }
}

// what handler return
pub enum HandlerResponse {
    Packet(Vec<u8>),
    Void,
}

// handler params
pub struct HandlerInput<'a> {
    session: &'a mut Session<'a>,
    data: Option<Vec<u8>>
}

pub struct Client<'a> {
    stream: Option<TcpStream>,
    buffer: [u8; 4096],
    session: Session<'a>,
}

// public methods
impl<'a> Client<'a> {
    pub fn new() -> Self {
        Self {
            stream: None,
            buffer: [0u8; 4096],
            session: Session::new(),
        }
    }

    pub fn connect(&mut self, host: &str, port: i16) {
        let addr = format!("{}:{}", host, port);
        match TcpStream::connect(&addr) {
            Ok(stream) => {
                self.stream = Some(stream);
                println!("Connected to {}", addr);
            },
            _ => {
                println!("Cannot connect");
            },
        }
    }

    pub fn handle_connection(
        &mut self, 
        handlers: Vec<fn(HandlerInput
    ) -> Result<u8, Error>>) {
        for handler in handlers {
            self.process(handler);
        }
    }
}

// private methods
impl<'a> Client<'a> {
    fn process<F>(&mut self, handler: F)
    where
        F: Fn(HandlerInput) -> Result<HandlerResponse, Error>
    {
        let response: Result<HandlerResponse, Error> = match self.handle_read() {
            Ok(server_response) => handler(HandlerInput {
                session: &mut self.session,
                data: Some(server_response),
            }),
            _ => handler(HandlerInput {
                session: &mut self.session,
                data: None,
            })
        };

        match response.unwrap() {
            HandlerResponse::Packet(data) => {
                self.handle_write(data).unwrap();
            },
            HandlerResponse::Void => {},
        }
    }

    fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
        let mut stream = self.stream.as_ref().unwrap();

        match stream.write(&packet) {
            Ok(_) => Ok(()),
            _ => Err(Error::new(ErrorKind::Other, "Write error")),
        }
    }

    fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
        let mut stream = self.stream.as_ref().unwrap();
        let mut buffer = self.buffer.as_mut();

        match stream.read(&mut buffer) {
            Ok(bytes_count) => {
                return Ok(buffer[ .. bytes_count].to_vec());
            },
            _ => Err(Error::new(ErrorKind::Other, "Read error")),
        }
    }
}

When I put lifetime on Client struct and then put lifetime on &'a mut self I got an error:

cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

Could you explain how to fix lifetimes here ?

UPDATED: I need a reference inside Session because I want to use the values of the session inside handlers, if I not use reference, I got the error:

move occurs because input.session.session_key has type Option<Vec<u8>>, which does not implement the Copy trait

The code how I use the Session:

fn handler(input: HandlerInput) {
    let hasher = Sha1::new();
    let digest = hasher
        .chain(input.session.username.unwrap())
        .chain(input.session.session_key.unwrap())
        .finalize();
}

Also sometimes I need to modify the input inside handler, something like:

let mut session = input.session;
session.session_key = Some(srp_client.session_key());

Upvotes: 0

Views: 221

Answers (1)

Finomnis
Finomnis

Reputation: 22446

I can see two problems:

  • Your short sample code is missing lifetime annotations
  • Your longer code is an implementation that is almost impossible to achieve with borrows, and therefore I suspect that this question is an XY-problem.

Quick fix of your short code sample

Your impl is missing lifetimes:

pub struct Session<'a> {
    pub session_key: Option<&'a Vec<u8>>,
    pub username: Option<&'a str>,
    pub password: Option<&'a str>,
}

impl<'a> Session<'a> {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
       }
    }
}

What you probably actually want

So my question is, why use borrows in the first place for Session? You technically only need the reference in HandlerInput. Then, both handlers see the same Session object to modify.

use std::io::{Error, ErrorKind, Read, Write};
use std::net::TcpStream;

// data which store values that I need to share between handlers
struct Session {
    pub session_key: Option<Vec<u8>>,
    pub username: Option<String>,
    pub password: Option<String>,
}

// not sure if this correct to set &None below, where to put the lifetime here ?
impl Session {
    pub fn new() -> Self {
        Self {
            session_key: None,
            username: None,
            password: None,
        }
    }
}

// what handler return
pub enum HandlerResponse {
    Packet(Vec<u8>),
    Void,
}

// handler params
pub struct HandlerInput<'a> {
    session: &'a mut Session,
    data: Option<Vec<u8>>,
}

pub struct Client {
    stream: Option<TcpStream>,
    buffer: [u8; 4096],
    session: Session,
}

// public methods
impl Client {
    pub fn new() -> Self {
        Self {
            stream: None,
            buffer: [0u8; 4096],
            session: Session::new(),
        }
    }

    pub fn connect(&mut self, host: &str, port: i16) {
        let addr = format!("{}:{}", host, port);
        match TcpStream::connect(&addr) {
            Ok(stream) => {
                self.stream = Some(stream);
                println!("Connected to {}", addr);
            }
            _ => {
                println!("Cannot connect");
            }
        }
    }

    pub fn handle_connection(
        &mut self,
        handlers: Vec<fn(HandlerInput) -> Result<HandlerResponse, Error>>,
    ) {
        for handler in handlers {
            self.process(handler);
        }
    }
}

// private methods
impl Client {
    fn process<F>(&mut self, handler: F)
    where
        F: Fn(HandlerInput) -> Result<HandlerResponse, Error>,
    {
        let response: Result<HandlerResponse, Error> = match self.handle_read() {
            Ok(server_response) => handler(HandlerInput {
                session: &mut self.session,
                data: Some(server_response),
            }),
            _ => handler(HandlerInput {
                session: &mut self.session,
                data: None,
            }),
        };

        match response.unwrap() {
            HandlerResponse::Packet(data) => {
                self.handle_write(data).unwrap();
            }
            HandlerResponse::Void => {}
        }
    }

    fn handle_write(&mut self, packet: Vec<u8>) -> Result<(), Error> {
        let mut stream = self.stream.as_ref().unwrap();

        match stream.write(&packet) {
            Ok(_) => Ok(()),
            _ => Err(Error::new(ErrorKind::Other, "Write error")),
        }
    }

    fn handle_read(&mut self) -> Result<Vec<u8>, Error> {
        let mut stream = self.stream.as_ref().unwrap();
        let mut buffer = self.buffer.as_mut();

        match stream.read(&mut buffer) {
            Ok(bytes_count) => {
                return Ok(buffer[..bytes_count].to_vec());
            }
            _ => Err(Error::new(ErrorKind::Other, "Read error")),
        }
    }
}

fn handler1(input: HandlerInput) -> Result<HandlerResponse, Error> {
    Ok(HandlerResponse::Void)
}

fn handler2(input: HandlerInput) -> Result<HandlerResponse, Error> {
    Ok(HandlerResponse::Void)
}

fn main() {
    let mut client = Client::new();
    client.connect("127.0.0.1", 8080);
    client.handle_connection(vec![handler1, handler2]);
}

Compiles fine and should work.

Upvotes: 2

Related Questions