I want to refactor part of my code. I want my processors
to return Vec
of functions instead of Vec
of results from calling this functions (as it implemented for now).
So, I have struct that implement trait Processor
which return Vec
of functions results. Each processor
take Vec
of functions depend on input and return Vec
of results from calling this functions. This is example of processor:
pub fn handler(input: &mut HandlerInput) -> HandlerResult {
Ok(HandlerOutput::Void)
}
pub struct AuthProcessor;
impl Processor for AuthProcessor {
fn process_input(input: HandlerInput) -> ProcessorResult {
let mut reader = Cursor::new(input.data.as_ref().unwrap());
let opcode = reader.read_u8().unwrap();
let handlers: Vec<HandlerFunction> = match opcode {
0 => {
vec![Box::new(handler)]
},
1 => {
vec![Box::new(handler)]
},
16 => {
vec![
Box::new(handler),
Box::new(handler)
]
}
_ => vec![],
};
Self::collect_responses(handlers, input)
}
}
This is how my types looks like:
pub struct HandlerInput<'a> {
pub session: &'a mut Session,
pub data: Option<&'a [u8]>,
}
pub enum HandlerOutput {
Data((u32, Vec<u8>, Vec<u8>)),
ConnectionRequest(String, u16),
Void,
}
pub type HandlerResult = Result<HandlerOutput, Error>;
pub type HandlerFunction<'a> = Box<dyn FnMut(&mut HandlerInput) -> HandlerResult + 'a>;
pub type ProcessorResult = Result<Vec<HandlerOutput>, Error>;
pub type ProcessorFunction<'a> = Box<dyn Fn(HandlerInput) -> ProcessorResult + Send + 'a>;
pub trait Processor {
fn process_input(input: HandlerInput) -> ProcessorResult;
fn collect_responses(
handlers: Vec<HandlerFunction>,
mut input: HandlerInput
) -> ProcessorResult {
let responses = handlers
.into_iter()
.filter_map(|mut func| func(&mut input).ok())
.collect::<Vec<HandlerOutput>>();
Ok(responses)
}
}
So, I tried to change my types a bit and tried to change my code, but got an errors like:
error: future cannot be sent between threads safely
--> src\client\mod.rs:215:9
|
215 | tokio::spawn(async move {
| ^^^^^^^^^^^^ future created by async block is not `Send`
|
= help: the trait `std::marker::Send` is not implemented for `dyn for<'r, 's> FnMut(&'r mut HandlerInput<'s>) -> Result<HandlerOutput, std::io::Error>`
In short what I trying to do:
- Fixed types
pub type ProcessorResult<'a> = Vec<HandlerFunction<'a>>;
pub type ProcessorFunction<'a> = Box<dyn Fn(&'a mut HandlerInput) -> ProcessorResult<'a> + Send + 'a>;
- Make processor to return
handlers
directly instead ofSelf::collect_responses(handlers, input)
- Refactored code inside task to get handlers list:
let handler_list = processors
.iter()
.map(|processor| processor(&mut handler_input))
.flatten()
.collect::<Vec<HandlerFunction>>();
for handler in handler_list {
match handler(&mut handler_input) {
Ok(output) => {
match output {
HandlerOutput::Data((opcode, header, body)) => {},
HandlerOutput::ConnectionRequest(host, port) => {},
HandlerOutput::Void => {},
}
},
_ => {},
};
sleep(Duration::from_millis(WRITE_TIMEOUT)).await;
}
This is sandbox to reproduce old version.
This is sandbox for what I want to achieve.
Could somebody explain what am I doing wrong ?