Rust passing closures and they lifetime - rust

Hi I try to pass my closure to mockall crate returning function in following way:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) {
dialogs
.expect_ask_for_game_decision_if_needed_and_set_game_to_launch()
.returning(ask_for_game_decision_if_needed_return_mock(steam_id));
}
pub fn ask_for_game_decision_if_needed_return_mock<'x, 'y>(
steam_id: String,
) -> Box<dyn Fn(&'x mut REvilConfig, &'y mut REvilManagerState) -> ResultDialogsErr<()> + Send> {
let default = move |_: &'x mut REvilConfig, state: &'y mut REvilManagerState| {
state.selected_game_to_launch = Some(steam_id.clone());
Ok(())
};
return Box::new(default);
}
but I get
error[E0308]: mismatched types
--> src\tests\integration.rs:128:14
|
128 | .returning(ask_for_game_decision_if_needed_return_mock(steam_id.to_string()));
| ^^^^^^^^^ lifetime mismatch
|
= note: expected associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output`
found associated type `<dyn Fn(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState) -> Result<(), error_stack::Report<DialogsErrors>> + Send as FnOnce<(&mut configStruct::REvilConfig, &mut rManager_header::REvilManagerState)>>::Output`
note: the lifetime requirement is introduced here
--> src\dialogs\dialogs.rs:54:10
|
54 | ) -> ResultDialogsErr<()>;
| ^^^^^^^^^^^^^^^^^^^^
P.S I'm writting mod manager for Resident Evil game that's why "REvil" :p
P.S2 In the end I managed to rewrite it like:
pub fn set_dialog_game_selection(dialogs: &mut Box<MockAsk>, steam_id: String) {
dialogs
.expect_ask_for_game_decision_if_needed_and_set_game_to_launch()
.returning(move |_, state| {
set_game_decision(steam_id.clone(), state);
Ok(())
});
}
pub fn set_game_decision(steam_id: String, state: &mut REvilManagerState) {
state.selected_game_to_launch = Some(steam_id);
}
But why my first approach doeasn't work? :(
Function signature I'm trying to mock is as follow:
pub type ResultDialogsErr<T> = Result<T, DialogsErrors>;
fn ask_for_game_decision_if_needed_and_set_game_to_launch(
&mut self,
config: &mut REvilConfig,
state: &mut REvilManagerState,
) -> ResultDialogsErr<()>;

If you remove the manual lifetime annotations, it works:
pub fn ask_for_game_decision_if_needed_return_mock(
steam_id: String,
) -> Box<dyn Fn(&mut REvilConfig, &mut REvilManagerState) -> DynResult<()> + Send> {
let default = move |_: &mut REvilConfig, state: &mut REvilManagerState| {
state.selected_game_to_launch = Some(steam_id.clone());
Ok(())
};
return Box::new(default);
}

Related

How do I create a HashMap with value of function?

I'm trying to set HashMap of functions in a struct to a field in the struct and call them like below code. But it has compiler error. How can I fix?
main.rs
use std::collections::HashMap;
struct A{
pub funcs: HashMap<&'static str, fn()->()>,
f1:i32,
f2:i32
}
impl A {
fn func1(&mut self) {self.f1+=1;println!("func1 has called {} time(s)",self.f1);}
fn func2(&mut self) {self.f2+=1;println!("func2 has called {} time(s)",self.f2);}
fn set_funcs(&mut self) {
self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
}
}
fn main() {
let mut a = A{funcs:HashMap::new(),f1:0,f2:0};
a.set_funcs();
a.funcs.get("f1").unwrap()();
}
compiler error
error[E0308]: mismatched types
--> src/main.rs:12:58
|
12 | self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
| ^^^^^^^^^^^ expected fn item, found a different fn item
|
= note: expected fn item `for<'r> fn(&'r mut A) {A::func1}`
found fn item `for<'r> fn(&'r mut A) {A::func2}`
error[E0308]: mismatched types
--> src/main.rs:12:18
|
12 | self.funcs = HashMap::from([("f1",Self::func1),("f2",Self::func2)]);
| ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found fn item
| |
| expected due to the type of this binding
|
= note: expected struct `HashMap<&'static str, fn()>`
found struct `HashMap<&str, for<'r> fn(&'r mut A) {A::func1}>`
Your functions have an argument: &mut self. self has type Self/A. A::func1 is fn(&mut A) -> () not fn() -> ()
use std::collections::HashMap;
struct A{
pub funcs: HashMap<&'static str, fn(&mut Self)->()>,
f1:i32,
f2:i32
}
impl A {
fn func1(&mut self) {self.f1+=1;println!("func1 has called {} time(s)",self.f1);}
fn func2(&mut self) {self.f2+=1;println!("func2 has called {} time(s)",self.f2);}
fn set_funcs(&mut self) {
self.funcs.insert("f1", Self::func1);
self.funcs.insert("f2", Self::func2);
}
}
fn main() {
let mut a = A{funcs:HashMap::new(),f1:0,f2:0};
a.set_funcs();
a.funcs.get("f1").unwrap()(&mut a);
}

How to fire async callback in rust

I'm trying to implement a StateMachine in Rust, but I encountered some problems while trying to fire the callback of StateMachine in a spawn thread.
Here is my StateMachine struct. The state is a generic T because I want to use it in many different scenerios, and I use a Vec to store all the callbacks those registered into this StateMachine.
At the very begining, I didn't use the lifetime 'a, but it will run into some lifetime problems, so I add the lifetime 'a by this suggestion: Idiomatic callbacks in Rust
pub struct StateMachine<'a, T> where T:Clone+Eq+'a {
state: RwLock<T>,
listeners2: Vec<Arc<Mutex<ListenerCallback<'a, T>>>>,
}
pub type ListenerCallback<'a, T> = dyn FnMut(T) -> Result<()> + Send + Sync + 'a ;
When the state is changed, the StateMachine will fire all the callbacks, as follows.
pub async fn try_set(&mut self, new_state:T) -> Result<()> {
if (block_on(self.state.read()).deref().eq(&new_state)) {
return Ok(())
}
// todo change the state
// fire every listener in spawn
let mut fire_results = vec![];
for listener in &mut self.listeners2 {
let state = new_state.clone();
let fire_listener = listener.clone();
fire_results.push(tokio::spawn(async move {
let mut guard = fire_listener.lock().unwrap();
guard.deref_mut()(state);
}));
}
// if fire result return Err, return it
for fire_result in fire_results {
fire_result.await?;
}
Ok(())
}
But it will cause a compilation error.
error[E0521]: borrowed data escapes outside of associated function
--> src/taf/taf-core/src/execution/state_machine.rs:54:33
|
15 | impl<'a,T> StateMachine<'a,T> where T:Clone+Eq+Send {
| -- lifetime `'a` defined here
...
34 | pub async fn try_set(&mut self, new_state:T) -> Result<()> {
| --------- `self` is a reference that is only valid in the associated function body
...
54 | let fire_listener = listener.clone();
| ^^^^^^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'a` must outlive `'static`
##########################################################
The full code is coupled with a lot of business logic, so I rewrite 2 demos as follows, the problems is the same. The first demo fire callback synchronously and it works, the second demo try to fire callback asynchronously, it encounter the same problem: self escapes the associated function body here.
First demo(it works):
use std::alloc::alloc;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex, RwLock};
use anyhow::Result;
use dashmap::DashMap;
struct StateMachine<'a,T> where T:Clone+Eq+'a {
state: T,
listeners: Vec<Box<Callback<'a, T>>>,
}
type Callback<'a, T> = dyn FnMut(T) -> Result<()> + Send + Sync + 'a;
impl<'a, T> StateMachine<'a,T> where T:Clone+Eq+'a {
pub fn new(init_state: T) -> Self {
StateMachine {
state: init_state,
listeners: vec![]
}
}
pub fn add_listener(&mut self, listener: Box<Callback<'a, T>>) -> Result<()> {
self.listeners.push(listener);
Ok(())
}
pub fn set(&mut self, new_state: T) -> Result<()> {
self.state = new_state.clone();
for listener in &mut self.listeners {
listener(new_state.clone());
}
Ok(())
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
enum ExeState {
Waiting,
Running,
Finished,
Failed,
}
struct Execution<'a> {
exec_id: String,
pub state_machine: StateMachine<'a, ExeState>,
}
struct ExecManager<'a> {
all_jobs: Arc<RwLock<DashMap<String, Execution<'a>>>>,
finished_jobs: Arc<RwLock<Vec<String>>>,
}
impl<'a> ExecManager<'a> {
pub fn new() -> Self {
ExecManager {
all_jobs: Arc::new(RwLock::new(DashMap::new())),
finished_jobs: Arc::new(RwLock::new(vec![]))
}
}
fn add_job(&mut self, job_id: String) {
let mut execution = Execution {
exec_id: job_id.clone(),
state_machine: StateMachine::new(ExeState::Waiting)
};
// add listener
let callback_finished_jobs = self.finished_jobs.clone();
let callback_job_id = job_id.clone();
execution.state_machine.add_listener( Box::new(move |new_state| {
println!("listener fired!, job_id {}", callback_job_id.clone());
if new_state == ExeState::Finished || new_state == ExeState::Failed {
let mut guard = callback_finished_jobs.write().unwrap();
guard.deref_mut().push(callback_job_id.clone());
}
Ok(())
}));
let mut guard = self.all_jobs.write().unwrap();
guard.deref_mut().insert(job_id, execution);
}
fn mock_exec(&mut self, job_id: String) {
let mut guard = self.all_jobs.write().unwrap();
let mut exec = guard.deref_mut().get_mut(&job_id).unwrap();
exec.state_machine.set(ExeState::Finished);
}
}
#[test]
fn test() {
let mut manager = ExecManager::new();
manager.add_job(String::from("job_id1"));
manager.add_job(String::from("job_id2"));
manager.mock_exec(String::from("job_id1"));
manager.mock_exec(String::from("job_id2"));
}
Second demo:
use std::alloc::alloc;
use std::ops::DerefMut;
use std::sync::{Arc, Mutex, RwLock};
use anyhow::Result;
use dashmap::DashMap;
use petgraph::algo::astar;
struct StateMachine<'a,T> where T:Clone+Eq+Send+'a {
state: T,
listeners: Vec<Arc<Mutex<Box<Callback<'a, T>>>>>,
}
type Callback<'a, T> = dyn FnMut(T) -> Result<()> + Send + Sync + 'a;
impl<'a, T> StateMachine<'a,T> where T:Clone+Eq+Send+'a {
pub fn new(init_state: T) -> Self {
StateMachine {
state: init_state,
listeners: vec![]
}
}
pub fn add_listener(&mut self, listener: Box<Callback<'a, T>>) -> Result<()> {
self.listeners.push(Arc::new(Mutex::new(listener)));
Ok(())
}
pub fn set(&mut self, new_state: T) -> Result<()> {
self.state = new_state.clone();
for listener in &mut self.listeners {
let spawn_listener = listener.clone();
tokio::spawn(async move {
let mut guard = spawn_listener.lock().unwrap();
guard.deref_mut()(new_state.clone());
});
}
Ok(())
}
}
#[derive(Clone, Eq, PartialEq, Hash)]
enum ExeState {
Waiting,
Running,
Finished,
Failed,
}
struct Execution<'a> {
exec_id: String,
pub state_machine: StateMachine<'a, ExeState>,
}
struct ExecManager<'a> {
all_jobs: Arc<RwLock<DashMap<String, Execution<'a>>>>,
finished_jobs: Arc<RwLock<Vec<String>>>,
}
impl<'a> ExecManager<'a> {
pub fn new() -> Self {
ExecManager {
all_jobs: Arc::new(RwLock::new(DashMap::new())),
finished_jobs: Arc::new(RwLock::new(vec![]))
}
}
fn add_job(&mut self, job_id: String) {
let mut execution = Execution {
exec_id: job_id.clone(),
state_machine: StateMachine::new(ExeState::Waiting)
};
// add listener
let callback_finished_jobs = self.finished_jobs.clone();
let callback_job_id = job_id.clone();
execution.state_machine.add_listener( Box::new(move |new_state| {
println!("listener fired!, job_id {}", callback_job_id.clone());
if new_state == ExeState::Finished || new_state == ExeState::Failed {
let mut guard = callback_finished_jobs.write().unwrap();
guard.deref_mut().push(callback_job_id.clone());
}
Ok(())
}));
let mut guard = self.all_jobs.write().unwrap();
guard.deref_mut().insert(job_id, execution);
}
fn mock_exec(&mut self, job_id: String) {
let mut guard = self.all_jobs.write().unwrap();
let mut exec = guard.deref_mut().get_mut(&job_id).unwrap();
exec.state_machine.set(ExeState::Finished);
}
}
#[test]
fn test() {
let mut manager = ExecManager::new();
manager.add_job(String::from("job_id1"));
manager.add_job(String::from("job_id2"));
manager.mock_exec(String::from("job_id1"));
manager.mock_exec(String::from("job_id2"));
}
Compile error of second demo:
error[E0521]: borrowed data escapes outside of associated function
--> generic/src/callback2.rs:34:34
|
15 | impl<'a, T> StateMachine<'a,T> where T:Clone+Eq+Send+'a {
| -- lifetime `'a` defined here
...
29 | pub fn set(&mut self, new_state: T) -> Result<()> {
| --------- `self` is a reference that is only valid in the associated function body
...
34 | let spawn_listener = listener.clone();
| ^^^^^^^^^^^^^^^^
| |
| `self` escapes the associated function body here
| argument requires that `'a` must outlive `'static`
|
= note: requirement occurs because of the type `std::sync::Mutex<Box<dyn FnMut(T) -> Result<(), anyhow::Error> + Send + Sync>>`, which makes the generic argument `Box<dyn FnMut(T) -> Result<(), anyhow::Error> + Send + Sync>` invariant
= note: the struct `std::sync::Mutex<T>` is invariant over the parameter `T`
= help: see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance
Tasks spawned with tokio::spawn() cannot use borrowed data (here, the data with lifetime 'a, whatever it may be). This is because there is not currently (and likely will never be) any way to guarantee that the borrowed data reliably outlives the spawned task.
You have two choices:
Fire the notifications without spawning. You can put the notification futures into a FuturesUnordered to run them all concurrently, but they will still all have to finish before try_set() does.
Remove the lifetime parameter; stop allowing callbacks that borrow data. Put 'static on your dyn types where necessary. Change the users of the StateMachine so they do not try to use borrowed data but use Arc instead, if necessary.
pub struct StateMachine<T> where T: Clone + Eq + 'static {
state: RwLock<T>,
listeners2: Vec<Arc<Mutex<ListenerCallback<T>>>>,
}
pub type ListenerCallback<T> = dyn FnMut(T) -> Result<()> + Send + Sync + 'static;

Returning traits with dyn

I've been trying to get this code to compile
pub trait Packet: PacketSerializer + ProtocolToID + Default {
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf>;
fn deserialize_gen(buf: &mut ByteBuf) -> Box<Self>;
}
impl<T: PacketSerializer + ProtocolToID + PacketHandler + Default> Packet for T
{
fn serialize_with_id(&self, ver: &ProtocolVersion) -> Box<ByteBuf> {
let mut buf = Box::new(ByteBuf::new());
buf.write_var_int(self.resolve_id(ver));
self.serialize(&mut buf, &ver);
buf
}
fn deserialize_gen(buf: &mut ByteBuf) -> Box<T> {
let mut p: T = Default::default();
p.deserialize(buf);
Box::new(p)
}
}
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
specifically invoke_packet_handler is supposed to return a Box<dyn Packet>
According to the docs, this should work https://doc.rust-lang.org/rust-by-example/trait/dyn.html if you "statically" define the trait so the compiler can see it.
I get the following error at runtime
error[E0038]: the trait `Packet` cannot be made into an object
--> src/serialize/packet.rs:43:61
|
43 | pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn Packet> {
| ^^^^^^^^^^^^^^^ `Packet` cannot be made into an object
I'm assuming this is because of the implementation for Packet? It's generic on every type that implements PacketSerializer, ProtocolToID, PacketHandler and Default
However,
pub fn invoke_packet_handler(id: i32, buf: &mut ByteBuf) -> Box<dyn PacketHandler> {
Box::new(clientbound::SetCompression { threshold: 256 })
}
does compile if I specify a single trait

How do I fix a lifetime issue when returning an iterator of all combinations between a newly received value and cached values?

I am trying to return an iterator of all combinations between a newly received value and cached values, but I got a lifetime issue.
use std::collections::HashMap;
pub struct Status {
// <i,Vec<u>>
old: HashMap<usize, Vec<usize>>,
}
impl<'a> Status {
pub fn new() -> Self {
Status {
old: HashMap::new(),
}
}
pub fn gen(&mut self, u: usize, i: usize) -> UserPairIter<'a> {
let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
UserPairIter::new(entry, u)
}
}
struct UserPairIter<'a> {
data: &'a mut Vec<usize>,
u: usize,
index: usize,
}
impl<'a> UserPairIter<'a> {
pub fn new(data: &'a mut Vec<usize>, u: usize) -> Self {
UserPairIter { data, u, index: 0 }
}
}
impl<'a> Iterator for UserPairIter<'a> {
type Item = (usize, usize);
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.data.len() {
self.data.push(self.u);
return None;
}
let result = (self.u, self.data[self.index]);
self.index += 1;
Some(result)
}
}
fn main() {}
When I compile, I get the following error message:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:16:50
|
16 | let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
| ^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 15:5...
--> src/main.rs:15:5
|
15 | / pub fn gen(&mut self, u: usize, i: usize) -> UserPairIter<'a> {
16 | | let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
17 | | UserPairIter::new(entry, u)
18 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:16:41
|
16 | let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
| ^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 8:1...
--> src/main.rs:8:1
|
8 | / impl<'a> Status {
9 | | pub fn new() -> Self {
10 | | Status {
11 | | old: HashMap::new(),
... |
18 | | }
19 | | }
| |_^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:16:41
|
16 | let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
First of all, do not put the lifetime generic in Status. If you need genericity in a function, put this parameter in function:
impl Status {
pub fn new() -> Self {
Status {
old: HashMap::new(),
}
}
pub fn gen<'a>(&mut self, u: usize, i: usize) -> UserPairIter<'a> {
let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
UserPairIter::new(entry, u)
}
}
Then the compiler says that it cannot infer a lifetime for self.old. Just give it the hint with &'a mut self so that the compiler understands that the lifetime of the UserPairIter is the same as the lifetime of Status:
impl Status {
pub fn new() -> Self {
Status {
old: HashMap::new(),
}
}
pub fn gen<'a>(&'a mut self, u: usize, i: usize) -> UserPairIter<'a> {
let entry: &'a mut Vec<usize> = self.old.entry(i).or_insert(Vec::new());
UserPairIter::new(entry, u)
}
}
And that is ok!
You do not need to say the type of entry, the compiler can infer it with the function signature:
pub fn gen<'a>(&'a mut self, u: usize, i: usize) -> UserPairIter<'a> {
let entry = self.old.entry(i).or_insert(Vec::new());
UserPairIter::new(entry, u)
}

Cannot infer a lifetime for a closure returning a boxed trait that contains a reference

I am trying to compile the following code (playground):
trait MockFutureTrait {
type Item;
}
struct MockFuture<T> {
item: T,
}
impl<T> MockFutureTrait for MockFuture<T> {
type Item = T;
}
struct FragMsgReceiver<'a, 'c: 'a> {
recv_dgram: &'a FnMut(&mut [u8])
-> Box<MockFutureTrait<Item = &mut [u8]> + 'c>,
}
fn constrain_handler<F>(f: F) -> F
where
F: FnMut(&mut [u8]) -> Box<MockFutureTrait<Item = &mut [u8]>>,
{
f
}
fn main() {
let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
});
let ref_recv_dgram = &mut recv_dgram;
let fmr = FragMsgReceiver {
recv_dgram: ref_recv_dgram,
};
}
And I get the compile error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:37
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #2 defined on the body at 27:44...
--> src/main.rs:27:44
|
27 | let mut recv_dgram = constrain_handler(|buf: &mut [u8]| {
| ____________________________________________^
28 | | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
29 | | });
| |_____^
note: ...so that expression is assignable (expected &mut [u8], found &mut [u8])
--> src/main.rs:28:37
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that expression is assignable (expected std::boxed::Box<MockFutureTrait<Item=&mut [u8]> + 'static>, found std::boxed::Box<MockFutureTrait<Item=&mut [u8]>>)
--> src/main.rs:28:9
|
28 | Box::new(MockFuture { item: buf }) as Box<MockFutureTrait<Item = &mut [u8]>>
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
I tried to add various lifetime hints, but I couldn't get this code to compile.
My previous related questions on SO about this:
Cannot infer a lifetime for a struct containing a reference to a closure: Solving the same problem, when the return value is a simple struct and not a trait.
How can multiple struct fields be generics that use the same higher-kinded lifetime?: About trying to solve this problem without Boxes. The answer suggests that for now I will have to use Box>.
Note that I am using the helper function constrain_handler according to a suggestion I got in question 2; it allows me to overcome a different compilation error.
It appears that you've missed a key takeaway of your previous questions and their duplicates:
Lifetime annotation for closure argument
Cannot infer a lifetime for a struct containing a reference to a closure
How to declare a lifetime for a closure argument
By declaring a type on the closure argument, you stop performing type inference for the arguments. This causes a new implicit lifetime to be generated by the closure, one which does not match your requirements. Just don't declare the type at all.
Next, you need to state that your closure is going to take a reference to some bytes and return a boxed trait object that will return some bytes of the same lifetime and contains a reference of that same lifetime:
struct FragMsgReceiver<'a> {
recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}
See Why is Box<Iterator<Item = &Foo> + 'a> needed? for more details about the + 'a syntax.
Then update constrain_handler to match:
struct FragMsgReceiver<'a> {
recv_dgram: &'a for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
}
fn constrain_handler<F>(f: F) -> F
where
F: for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
f
}
fn main() {
let mut recv_dgram = constrain_handler(|buf| Box::new(MockFuture { item: buf }));
let fmr = FragMsgReceiver {
recv_dgram: &mut recv_dgram,
};
}
The whole thing can be made simpler if you just take a generic closure directly:
struct FragMsgReceiver<R>
where
R: for<'b> FnMut(&'b mut [u8])
-> Box<MockFutureTrait<Item = &'b mut [u8]> + 'b>,
{
recv_dgram: R,
}
fn main() {
let fmr = FragMsgReceiver {
recv_dgram: |buf| Box::new(MockFuture { item: buf }),
};
}

Resources