My struct ReadingState
takes the function recv_dgram
as argument in its new()
method. recv_dgram
takes as an argument a buffer with some lifetime 'r
, and returns a Future
of a certain type. The Item
of this future contains the buffer that was fed as an argument, with the same lifetime 'r
.
This is how ReadingState
looks like:
struct FragMsgReceiver<'a, A, FUNC: 'a>
where
FUNC: for<'r> FnMut(&'r [u8])
-> Future<Item = (&'r [u8], usize, A), Error = io::Error>,
{
frag_state_machine: FragStateMachine,
recv_dgram: &'a mut FUNC,
get_cur_instant: &'a mut FnMut() -> Instant,
}
struct ReadingState<'a, 'c, A, FUNC: 'a, F>
where
F: Future<Item = (&'c mut [u8], usize, A), Error = io::Error>,
FUNC: for<'r> FnMut(&'r [u8])
-> Future<Item = (&'r [u8], usize, A), Error = io::Error>,
{
frag_msg_receiver: FragMsgReceiver<'a, A, FUNC>,
temp_buff: Vec<u8>,
res_buff: &'c mut [u8],
opt_read_future: Option<F>,
}
The return type of FUNC
is not the same as F
because they use different lifetimes.
The structs by themselves can compile, but I can not use them correctly in the rest of my code. For example, this happens when I try to call frag_msg_receiver.recv_dgram
and assign the result to the field opt_read_future
of ReadingState
:
error[E0308]: match arms have incompatible types
--> src/frag_msg_receiver.rs:80:30
|
80 | let mut fdgram = match mem::replace(&mut reading_state.opt_read_future, None) {
| ______________________________^
81 | | Some(read_future) => read_future,
82 | | None => (*reading_state.frag_msg_receiver.recv_dgram)(
83 | | &mut reading_state.temp_buff),
84 | | };
| |_____________^ expected type parameter, found trait frag_msg_receiver::futures::Future
|
= note: expected type `F`
found type `frag_msg_receiver::futures::Future<Item=(&[u8], usize, A), Error=std::io::Error> + 'static`
A dream solution (this is not valid Rust code) will be something of the form:
struct ReadingState<'a, 'c, A, FUNC: 'a, F>
where for <'r> {
F: Future<Item = (&'r mut [u8], usize, A), Error = io::Error>,
FUNC: FnMut(&'r [u8]) -> F,
}
{
// ...
}
I don't know how to achieve this with the existing syntax.
Edit: I made the smallest possible self contained example I could, but it doesn't compile for possibly different reasons. I am including it here (playground):
trait MockFutureTrait {
type Item;
fn get_item(self) -> Self::Item;
}
type FnTraitObject = FnMut(&mut [u8]) -> MockFutureTrait<Item=&mut [u8]>;
struct MockFuture<T> {
item: T,
}
impl<T> MockFutureTrait for MockFuture<T> {
type Item=T;
fn get_item(self) -> Self::Item {
self.item
}
}
struct FragMsgReceiver<'a> {
recv_dgram: &'a mut FnTraitObject,
}
struct RecvMsg<'a,'c,F>
where F: MockFutureTrait<Item=&'c mut [u8]> {
frag_msg_receiver: FragMsgReceiver<'a>,
res_buff: &'c mut [u8],
read_future: F,
}
fn main() {
let mut recv_dgram = |buf: &mut [u8]| {
MockFuture {
item: buf,
}
};
let fmr = FragMsgReceiver {
recv_dgram: &mut recv_dgram,
};
}
The compilation error I get:
error[E0271]: type mismatch resolving `for<'r> <[closure@src/main.rs:33:26: 37:6] as std::ops::FnOnce<(&'r mut [u8],)>>::Output == MockFutureTrait<Item=&'r mut [u8]> + 'static`
--> src/main.rs:40:21
|
40 | recv_dgram: &mut recv_dgram,
| ^^^^^^^^^^^^^^^ expected struct `MockFuture`, found trait MockFutureTrait
|
= note: expected type `MockFuture<&mut [u8]>`
found type `MockFutureTrait<Item=&mut [u8]> + 'static`
= note: required for the cast to the object type `for<'r> std::ops::FnMut(&'r mut [u8]) -> MockFutureTrait<Item=&'r mut [u8]> + 'static + 'static`
error: aborting due to previous error
error: Could not compile `noncompiling_lifetime_trait`.
I'm not sure that I know what I'm doing, and why the compile problems changed. You might have an idea.
What you're hoping to do isn't possible as of Rust 1.20. You need generic associated types in order to bind the correct lifetime on the type parameter
F
. The solution would look like this (obviously, I can't test it because generic associated types are not implemented yet):Note: I left the
F
type parameter onReadingState
because the type is slightly different fromFragFutureFamily::F
, though if you can make the types agree, you could change the type ofopt_read_future
toOption<FF::F<'c>>
.As a workaround, you could use
Box<Future<...>>
instead of a type parameter for theFuture
type.