From 9277ddafdf7c1a3cafe17e66b43fbd222f7f89cc Mon Sep 17 00:00:00 2001 From: Sergio Benitez Date: Sun, 28 Jun 2020 14:01:06 -0700 Subject: [PATCH] Swap 'Rocket' manually without using 'replace_with'. --- core/lib/src/ext.rs | 52 +----------------------------------------- core/lib/src/rocket.rs | 20 ++++++++++++++-- 2 files changed, 19 insertions(+), 53 deletions(-) diff --git a/core/lib/src/ext.rs b/core/lib/src/ext.rs index 0595d625..81236216 100644 --- a/core/lib/src/ext.rs +++ b/core/lib/src/ext.rs @@ -2,7 +2,7 @@ use std::io::{self, Cursor}; use std::pin::Pin; use std::task::{Poll, Context}; -use futures::{ready, Future, future::BoxFuture, stream::Stream}; +use futures::{ready, future::BoxFuture, stream::Stream}; use tokio::io::{AsyncRead, AsyncReadExt as _}; use crate::http::hyper; @@ -111,53 +111,3 @@ impl AsyncRead for AsyncReadBody { } } } - -// The code below was adapted from the `replace_with` crate and reproduced here -// under the rights granted by the MIT license. The code is copyright the -// `replace_with` developers. See LICENSE-MIT for the full text. - -struct OnUnwind(std::mem::ManuallyDrop); - -impl Drop for OnUnwind { - #[inline(always)] - fn drop(&mut self) { - (unsafe { std::ptr::read(&*self.0) })(); - } -} - -#[inline(always)] -pub async fn async_on_unwind(f: F, p: P) -> T - where F: FnOnce() -> Fut, Fut: Future, -{ - let x = OnUnwind(std::mem::ManuallyDrop::new(p)); - let t = f().await; - let _ = unsafe { std::ptr::read(&*x.0) }; - std::mem::forget(x); - t -} - -#[inline] -pub async fn async_replace_with_or_else(dest: &mut T, d: D, f: F) - where Fut: Future, - F: FnOnce(T) -> Fut, - D: FnOnce() -> T, -{ - unsafe { - let old = std::ptr::read(dest); - let new = async_on_unwind( - || async move { f(old).await }, - || std::ptr::write(dest, d()), - ).await; - - std::ptr::write(dest, new); - } -} - - -#[inline] -pub async fn async_replace_with(dest: &mut T, f: F) - where Fut: Future, - F: FnOnce(T) -> Fut, -{ - async_replace_with_or_else(dest, || std::process::abort(), f).await -} diff --git a/core/lib/src/rocket.rs b/core/lib/src/rocket.rs index f92fe8fd..f830633c 100644 --- a/core/lib/src/rocket.rs +++ b/core/lib/src/rocket.rs @@ -24,7 +24,7 @@ use crate::outcome::Outcome; use crate::error::{LaunchError, LaunchErrorKind}; use crate::fairing::{Fairing, Fairings}; use crate::logger::PaintExt; -use crate::ext::{AsyncReadExt, async_replace_with}; +use crate::ext::AsyncReadExt; use crate::shutdown::{ShutdownHandle, ShutdownHandleManaged}; use crate::http::{Method, Status, Header}; @@ -109,6 +109,21 @@ impl Rocket { self } + // Create a "dummy" instance of `Rocket` to use while mem-swapping `self`. + fn dummy() -> Rocket { + Rocket { + manifest: vec![], + config: Config::development(), + router: Router::new(), + default_catchers: HashMap::new(), + catchers: HashMap::new(), + managed_state: Container::new(), + fairings: Fairings::new(), + shutdown_handle: ShutdownHandle(mpsc::channel(1).0), + shutdown_receiver: None, + } + } + // Instead of requiring the user to individually `await` each call to // `attach()`, some operations are queued in `self.pending`. Functions that // want to provide read access to any data from the Cargo, such as @@ -133,7 +148,8 @@ impl Rocket { PreLaunchOp::Mount(base, routes) => self._mount(base, routes), PreLaunchOp::Register(catchers) => self._register(catchers), PreLaunchOp::Attach(fairing) => { - async_replace_with(self, |rocket| rocket._attach(fairing)).await; + let rocket = mem::replace(self, Rocket::dummy()); + *self = rocket._attach(fairing).await; self.manifest.append(&mut manifest); manifest = mem::replace(&mut self.manifest, vec![]); }