The code in question:
//! Echo server running on a single core microcontroller
fn main() {
let Serial { mut tx, mut rx } = Serial::new().unwrap();
// `bytes` is an infinite stream of bytes
let mut bytes = rx.bytes();
let mut pending_write: Option<Write> = None;
loop {
// If there's new data
if let Async::Ready(byte) = bytes.poll() {
// Drive any pending write to its completion because we are going
// to ...
pending_write.take().map(|w| w.wait());
//* `Tx` loan ends here because `pending_write` is always `None` at
//* this point
// ... queue a new write
pending_write = Some(tx.write(byte));
//* ^ `Tx` loan starts here
}
// Check if the pending write completed
if let Some(Async::Ready(())) =
pending_write.as_mut().map(|w| w.poll())
{
// Done
pending_write = None;
}
// Other "concurrent" tasks could be running here
}
}
See the appendix for the signature of the involved methods and struct
s.
//
are the original comments. //*
are additional comments to explain why
this code should work.
Right now this errors with:
error[E0499]: cannot borrow `tx` as mutable more than once at a time
--> examples/aio-echo.rs:39:34
|
39 | pending_write = Some(tx.write(byte));
| ^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
50 | }
| - first borrow ends here
error: aborting due to previous error
because the compiler assumes that pending_write
borrows tx
for the whole
scope of the loop
. But, tx
is actually only borrowed from pending_write = Some(tx.write(byte))
up to the next iteration’s pending_write.take().map(|w| w.wait())
thus tx
is not being borrowed at the moment that pending_write = Some(tx.write(byte))
must be executed.
Will the planned NLL feature accept this code? AIUI, the borrow checker will
gain the ability to keep track of loans that are smaller than the immediately
outer scope but it seems that the borrow checker must also be aware that the
None
variant doesn’t borrow anything (I don’t know if it does that already).
Appendix
enum Async {
NotReady,
Ready(T),
}
trait Future {
fn poll(&mut self) -> Async<Self::Item>;
fn wait(mut self) -> Self::Item {
loop {
if let Async::Ready(item) = self.wait() {
return item;
}
}
}
}
/// Serial communication interface
struct Serial {
/// Transmitter
tx: Tx,
/// Receiver
rx: Rx,
}
/// Transmitter
struct Tx {
_0: (),
}
impl Tx {
/// Sends a byte through the transmitter
///
/// This returns a future because the transmitter may be already in the
/// process of sending one byte.
fn write<'t>(&'t mut self, byte: u8) -> Write<'t> {
// ..
}
}
/// A transmitter write request
struct Write<'t> {
_tx: PhantomData<&'t mut Tx>,
byte: u8,
done: bool,
}
impl<'t> Future for Write<'t> {
// ..
}