Make use of NLL to clean up handshaking logic (#576)

This commit is contained in:
Anthony Ramine
2022-01-26 11:18:28 +01:00
committed by GitHub
parent 7de2ccc1a3
commit 556447c130
2 changed files with 85 additions and 93 deletions

View File

@@ -83,3 +83,32 @@ jobs:
- name: Check minimal versions - name: Check minimal versions
run: cargo clean; cargo update -Zminimal-versions; cargo check run: cargo clean; cargo update -Zminimal-versions; cargo check
if: matrix.rust == 'nightly' if: matrix.rust == 'nightly'
msrv:
name: Check MSRV (${{ matrix.rust }})
needs: [style]
strategy:
matrix:
rust:
- 1.46 # never go past Hyper's own MSRV
os:
- ubuntu-latest
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Install Rust (${{ matrix.rust }})
uses: actions-rs/toolchain@v1
with:
profile: minimal
toolchain: ${{ matrix.rust }}
override: true
- name: Check
uses: actions-rs/cargo@v1
with:
command: check

View File

@@ -126,7 +126,7 @@ use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::task::{Context, Poll}; use std::task::{Context, Poll};
use std::time::Duration; use std::time::Duration;
use std::{convert, fmt, io, mem}; use std::{fmt, io};
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf}; use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
use tracing::instrument::{Instrument, Instrumented}; use tracing::instrument::{Instrument, Instrumented};
@@ -301,8 +301,8 @@ enum Handshaking<T, B: Buf> {
Flushing(Instrumented<Flush<T, Prioritized<B>>>), Flushing(Instrumented<Flush<T, Prioritized<B>>>),
/// State 2. Connection is waiting for the client preface. /// State 2. Connection is waiting for the client preface.
ReadingPreface(Instrumented<ReadPreface<T, Prioritized<B>>>), ReadingPreface(Instrumented<ReadPreface<T, Prioritized<B>>>),
/// Dummy state for `mem::replace`. /// State 3. Handshake is done, polling again would panic.
Empty, Done,
} }
/// Flush a Sink /// Flush a Sink
@@ -387,7 +387,8 @@ where
.expect("invalid SETTINGS frame"); .expect("invalid SETTINGS frame");
// Create the handshake future. // Create the handshake future.
let state = Handshaking::from(codec); let state =
Handshaking::Flushing(Flush::new(codec).instrument(tracing::trace_span!("flush")));
drop(entered); drop(entered);
@@ -1269,9 +1270,10 @@ where
let span = self.span.clone(); // XXX(eliza): T_T let span = self.span.clone(); // XXX(eliza): T_T
let _e = span.enter(); let _e = span.enter();
tracing::trace!(state = ?self.state); tracing::trace!(state = ?self.state);
use crate::server::Handshaking::*;
self.state = if let Flushing(ref mut flush) = self.state { loop {
match &mut self.state {
Handshaking::Flushing(flush) => {
// We're currently flushing a pending SETTINGS frame. Poll the // We're currently flushing a pending SETTINGS frame. Poll the
// flush future, and, if it's completed, advance our state to wait // flush future, and, if it's completed, advance our state to wait
// for the client preface. // for the client preface.
@@ -1285,27 +1287,15 @@ where
flushed flushed
} }
}; };
Handshaking::from(ReadPreface::new(codec)) self.state = Handshaking::ReadingPreface(
} else { ReadPreface::new(codec).instrument(tracing::trace_span!("read_preface")),
// Otherwise, we haven't actually advanced the state, but we have );
// to replace it with itself, because we have to return a value. }
// (note that the assignment to `self.state` has to be outside of Handshaking::ReadingPreface(read) => {
// the `if let` block above in order to placate the borrow checker). let codec = ready!(Pin::new(read).poll(cx)?);
mem::replace(&mut self.state, Handshaking::Empty)
}; self.state = Handshaking::Done;
let poll = if let ReadingPreface(ref mut read) = self.state {
// We're now waiting for the client preface. Poll the `ReadPreface`
// future. If it has completed, we will create a `Connection` handle
// for the connection.
Pin::new(read).poll(cx)
// Actually creating the `Connection` has to occur outside of this
// `if let` block, because we've borrowed `self` mutably in order
// to poll the state and won't be able to borrow the SETTINGS frame
// as well until we release the borrow for `poll()`.
} else {
unreachable!("Handshake::poll() state was not advanced completely!")
};
poll?.map(|codec| {
let connection = proto::Connection::new( let connection = proto::Connection::new(
codec, codec,
Config { Config {
@@ -1324,8 +1314,14 @@ where
if let Some(sz) = self.builder.initial_target_connection_window_size { if let Some(sz) = self.builder.initial_target_connection_window_size {
c.set_target_window_size(sz); c.set_target_window_size(sz);
} }
Ok(c)
}) return Poll::Ready(Ok(c));
}
Handshaking::Done => {
panic!("Handshaking::poll() called again after handshaking was complete")
}
}
}
} }
} }
@@ -1548,42 +1544,9 @@ where
#[inline] #[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self { match *self {
Handshaking::Flushing(_) => write!(f, "Handshaking::Flushing(_)"), Handshaking::Flushing(_) => f.write_str("Flushing(_)"),
Handshaking::ReadingPreface(_) => write!(f, "Handshaking::ReadingPreface(_)"), Handshaking::ReadingPreface(_) => f.write_str("ReadingPreface(_)"),
Handshaking::Empty => write!(f, "Handshaking::Empty"), Handshaking::Done => f.write_str("Done"),
} }
} }
} }
impl<T, B> convert::From<Flush<T, Prioritized<B>>> for Handshaking<T, B>
where
T: AsyncRead + AsyncWrite,
B: Buf,
{
#[inline]
fn from(flush: Flush<T, Prioritized<B>>) -> Self {
Handshaking::Flushing(flush.instrument(tracing::trace_span!("flush")))
}
}
impl<T, B> convert::From<ReadPreface<T, Prioritized<B>>> for Handshaking<T, B>
where
T: AsyncRead + AsyncWrite,
B: Buf,
{
#[inline]
fn from(read: ReadPreface<T, Prioritized<B>>) -> Self {
Handshaking::ReadingPreface(read.instrument(tracing::trace_span!("read_preface")))
}
}
impl<T, B> convert::From<Codec<T, Prioritized<B>>> for Handshaking<T, B>
where
T: AsyncRead + AsyncWrite,
B: Buf,
{
#[inline]
fn from(codec: Codec<T, Prioritized<B>>) -> Self {
Handshaking::from(Flush::new(codec))
}
}