use std::alloc::Layout; use std::fmt; use std::future::{self, Future}; use std::mem::{self, ManuallyDrop}; use std::pin::Pin; use std::ptr; use std::task::{Context, Poll};
/// A reusable `Pin<Box<dyn Future<Output = T> + Send + 'a>>`. /// /// This type lets you replace the future stored in the box without /// reallocating when the size and alignment permits this. pubstruct ReusableBoxFuture<'a, T> {
boxed: Pin<Box<dyn Future<Output = T> + Send + 'a>>,
}
impl<'a, T> ReusableBoxFuture<'a, T> { /// Create a new `ReusableBoxFuture<T>` containing the provided future. pubfn new<F>(future: F) -> Self where
F: Future<Output = T> + Send + 'a,
{ Self {
boxed: Box::pin(future),
}
}
/// Replace the future currently stored in this box. /// /// This reallocates if and only if the layout of the provided future is /// different from the layout of the currently stored future. pubfn set<F>(&mutself, future: F) where
F: Future<Output = T> + Send + 'a,
{ iflet Err(future) = self.try_set(future) {
*self = Self::new(future);
}
}
/// Replace the future currently stored in this box. /// /// This function never reallocates, but returns an error if the provided /// future has a different size or alignment from the currently stored /// future. pubfn try_set<F>(&mutself, future: F) -> Result<(), F> where
F: Future<Output = T> + Send + 'a,
{ // If we try to inline the contents of this function, the type checker complains because // the bound `T: 'a` is not satisfied in the call to `pending()`. But by putting it in an // inner function that doesn't have `T` as a generic parameter, we implicitly get the bound // `F::Output: 'a` transitively through `F: 'a`, allowing us to call `pending()`. #[inline(always)] fn real_try_set<'a, F>(
this: &mut ReusableBoxFuture<'a, F::Output>,
future: F,
) -> Result<(), F> where
F: Future + Send + 'a,
{ // future::Pending<T> is a ZST so this never allocates. let boxed = mem::replace(&mut this.boxed, Box::pin(future::pending()));
reuse_pin_box(boxed, future, |boxed| this.boxed = Pin::from(boxed))
}
real_try_set(self, future)
}
/// Get a pinned reference to the underlying future. pubfn get_pin(&mutself) -> Pin<&mut (dyn Future<Output = T> + Send)> { self.boxed.as_mut()
}
/// Poll the future stored inside this box. pubfn poll(&mutself, cx: &mut Context<'_>) -> Poll<T> { self.get_pin().poll(cx)
}
}
impl<T> Future for ReusableBoxFuture<'_, T> { type Output = T;
/// Poll the future stored inside this box. fn poll(self: Pin<&mutSelf>, cx: &mut Context<'_>) -> Poll<T> {
Pin::into_inner(self).get_pin().poll(cx)
}
}
// The only method called on self.boxed is poll, which takes &mut self, so this // struct being Sync does not permit any invalid access to the Future, even if // the future is not Sync. unsafeimpl<T> Sync for ReusableBoxFuture<'_, T> {}
fn reuse_pin_box<T: ?Sized, U, O, F>(boxed: Pin<Box<T>>, new_value: U, callback: F) -> Result<O, U> where
F: FnOnce(Box<U>) -> O,
{ let layout = Layout::for_value::<T>(&*boxed); if layout != Layout::new::<U>() { return Err(new_value);
}
// SAFETY: We don't ever construct a non-pinned reference to the old `T` from now on, and we // always drop the `T`. let raw: *mut T = Box::into_raw(unsafe { Pin::into_inner_unchecked(boxed) });
// When dropping the old value panics, we still want to call `callback` — so move the rest of // the code into a guard type. let guard = CallOnDrop::new(|| { let raw: *mut U = raw.cast::<U>(); unsafe { raw.write(new_value) };
// SAFETY: // - `T` and `U` have the same layout. // - `raw` comes from a `Box` that uses the same allocator as this one. // - `raw` points to a valid instance of `U` (we just wrote it in). let boxed = unsafe { Box::from_raw(raw) };
callback(boxed)
});
// Drop the old value. unsafe { ptr::drop_in_place(raw) };
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.