Reputation: 1922
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 typeOption<Vec<u8>>
, which does not implement theCopy
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
Reputation: 22446
I can see two problems:
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,
}
}
}
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