From 41e102f37fe540ba51b8462e80d10a53479c7949 Mon Sep 17 00:00:00 2001 From: arduano Date: Tue, 26 Dec 2023 17:16:38 +1100 Subject: [PATCH] Removed redundant type argument from Lazy --- src/lib.rs | 130 +++++++++++++++++++++++------------------------------ 1 file changed, 56 insertions(+), 74 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bac0244..07dfb5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -961,9 +961,9 @@ mod test { } } -union LazyState { +union LazyState { running: ManuallyDrop, - ready: ManuallyDrop, + ready: ManuallyDrop, _empty: (), } @@ -1006,7 +1006,7 @@ union LazyState { /// use std::future::Future; /// /// type H = impl Future; -/// static LAZY: Lazy = Lazy::new(async { 4 }); +/// static LAZY: Lazy = Lazy::new(async { 4 }); /// ``` /// /// However, it is possile to use if you have a named struct that implements `Future`: @@ -1023,7 +1023,7 @@ union LazyState { /// } /// } /// -/// static LAZY: Lazy = Lazy::new(F); +/// static LAZY: Lazy = Lazy::new(F); /// ``` /// /// And this type of struct can still use `async` syntax in its implementation: @@ -1042,25 +1042,22 @@ union LazyState { /// } /// } /// -/// static LAZY: Lazy = Lazy::new(F(None)); +/// static LAZY: Lazy = Lazy::new(F(None)); /// ``` -pub struct Lazy { - value: UnsafeCell>, +pub struct Lazy { + value: UnsafeCell>, inner: Inner, } // Safety: our UnsafeCell should be treated like (RwLock, Mutex) -unsafe impl Sync for Lazy {} -unsafe impl Send for Lazy {} -impl Unpin for Lazy {} -impl RefUnwindSafe for Lazy {} -impl UnwindSafe for Lazy {} +unsafe impl Sync for Lazy where F::Output: Send + Sync {} +unsafe impl Send for Lazy where F::Output: Send + Sync {} +impl Unpin for Lazy where F::Output: Unpin {} +impl RefUnwindSafe for Lazy where F::Output: RefUnwindSafe + UnwindSafe {} +impl UnwindSafe for Lazy where F::Output: UnwindSafe {} -impl Lazy -where - F: Future, -{ +impl Lazy { /// Creates a new lazy value with the given initializing future. pub const fn new(future: F) -> Self { Self::from_future(future) @@ -1071,7 +1068,7 @@ where /// This is equivalent to calling `.await` on a pinned reference, but is more explicit. /// /// The [Pin::static_ref] function may be useful if this is a static value. - pub async fn get(self: Pin<&Self>) -> Pin<&T> { + pub async fn get(self: Pin<&Self>) -> Pin<&F::Output> { self.await } } @@ -1086,26 +1083,23 @@ enum Step<'a> { /// A helper struct for both of [Lazy]'s [IntoFuture]s /// /// Note: the Lazy value may or may not be pinned, depending on what public struct wraps this one. -struct LazyFuture<'a, T, F> { - lazy: &'a Lazy, +struct LazyFuture<'a, F: Future> { + lazy: &'a Lazy, step: Step<'a>, // This is needed to guarantee Inner's refcount never overflows _pin: PhantomPinned, } -impl<'a, T, F> LazyFuture<'a, T, F> -where - F: Future, -{ - fn poll(&mut self, cx: &mut task::Context<'_>) -> task::Poll<&'a T> { - struct QuickReadyGuard<'a, T, F> { - this: &'a Lazy, - value: ManuallyDrop, +impl<'a, F: Future> LazyFuture<'a, F> { + fn poll(&mut self, cx: &mut task::Context<'_>) -> task::Poll<&'a F::Output> { + struct QuickReadyGuard<'a, F: Future> { + this: &'a Lazy, + value: ManuallyDrop, guard: QuickInitGuard<'a>, } // Prevent double-drop in case of panic in ManuallyDrop::drop - impl Drop for QuickReadyGuard<'_, T, F> { + impl Drop for QuickReadyGuard<'_, F> { fn drop(&mut self) { // Safety: the union is currently empty and must be filled with a ready value unsafe { @@ -1116,15 +1110,15 @@ where } } - struct ReadyGuard<'a, T, F> { - this: &'a Lazy, - value: ManuallyDrop, + struct ReadyGuard<'a, F: Future> { + this: &'a Lazy, + value: ManuallyDrop, // head is a field here to ensure it is dropped after our Drop head: QueueHead<'a>, } // Prevent double-drop in case of panic in ManuallyDrop::drop - impl Drop for ReadyGuard<'_, T, F> { + impl Drop for ReadyGuard<'_, F> { fn drop(&mut self) { // Safety: the union is currently empty and must be filled with a ready value unsafe { @@ -1223,14 +1217,11 @@ where } /// A helper struct for [Lazy]'s [IntoFuture] -pub struct LazyFuturePin<'a, T, F>(LazyFuture<'a, T, F>); +pub struct LazyFuturePin<'a, F: Future>(LazyFuture<'a, F>); -impl<'a, T, F> IntoFuture for Pin<&'a Lazy> -where - F: Future, -{ - type Output = Pin<&'a T>; - type IntoFuture = LazyFuturePin<'a, T, F>; +impl<'a, F: Future> IntoFuture for Pin<&'a Lazy> { + type Output = Pin<&'a F::Output>; + type IntoFuture = LazyFuturePin<'a, F>; fn into_future(self) -> Self::IntoFuture { // Safety: this is Pin::deref, but with a lifetime of 'a let lazy = unsafe { Pin::into_inner_unchecked(self) }; @@ -1238,12 +1229,9 @@ where } } -impl<'a, T, F> Future for LazyFuturePin<'a, T, F> -where - F: Future, -{ - type Output = Pin<&'a T>; - fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll> { +impl<'a, F: Future> Future for LazyFuturePin<'a, F> { + type Output = Pin<&'a F::Output>; + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll> { // Safety: we don't move anything that needs to be pinned. let inner = unsafe { &mut Pin::into_inner_unchecked(self).0 }; // Safety: because the original Lazy was pinned, the T it produces is also pinned @@ -1251,47 +1239,38 @@ where } } -impl Lazy -where - F: Future + Unpin, -{ +impl Lazy { /// Forces the evaluation of this lazy value and returns a reference to the result. /// /// This is equivalent to calling `.await` on a reference, but may be clearer to call /// explicitly. /// /// Unlike [Self::get], this does not require pinning the object. - pub async fn get_unpin(&self) -> &T { + pub async fn get_unpin(&self) -> &F::Output { self.await } } /// A helper struct for [Lazy]'s [IntoFuture] -pub struct LazyFutureUnpin<'a, T, F>(LazyFuture<'a, T, F>); +pub struct LazyFutureUnpin<'a, F: Future>(LazyFuture<'a, F>); -impl<'a, T, F> IntoFuture for &'a Lazy -where - F: Future + Unpin, -{ - type Output = &'a T; - type IntoFuture = LazyFutureUnpin<'a, T, F>; +impl<'a, F: Future + Unpin> IntoFuture for &'a Lazy { + type Output = &'a F::Output; + type IntoFuture = LazyFutureUnpin<'a, F>; fn into_future(self) -> Self::IntoFuture { LazyFutureUnpin(LazyFuture { lazy: self, step: Step::Start, _pin: PhantomPinned }) } } -impl<'a, T, F> Future for LazyFutureUnpin<'a, T, F> -where - F: Future + Unpin, -{ - type Output = &'a T; - fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<&'a T> { +impl<'a, F: Future + Unpin> Future for LazyFutureUnpin<'a, F> { + type Output = &'a F::Output; + fn poll(self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> task::Poll<&'a F::Output> { // Safety: we don't move anything that needs to be pinned. unsafe { Pin::into_inner_unchecked(self) }.0.poll(cx) } } -impl Lazy { +impl Lazy { /// Creates a new lazy value with the given initializing future. /// /// This is equivalent to [Self::new] but with no type bound. @@ -1303,7 +1282,7 @@ impl Lazy { } /// Creates an already-initialized lazy value. - pub const fn with_value(value: T) -> Self { + pub const fn with_value(value: F::Output) -> Self { Self { value: UnsafeCell::new(LazyState { ready: ManuallyDrop::new(value) }), inner: Inner::new_ready(), @@ -1311,7 +1290,7 @@ impl Lazy { } /// Gets the value without blocking or starting the initialization. - pub fn try_get(&self) -> Option<&T> { + pub fn try_get(&self) -> Option<&F::Output> { let state = self.inner.state.load(Ordering::Acquire); if state & READY_BIT == 0 { @@ -1326,7 +1305,7 @@ impl Lazy { /// /// This requires mutable access to self, so rust's aliasing rules prevent any concurrent /// access and allow violating the usual rules for accessing this cell. - pub fn try_get_mut(self: Pin<&mut Self>) -> Option> { + pub fn try_get_mut(self: Pin<&mut Self>) -> Option> { // Safety: unpinning for access let this = unsafe { self.get_unchecked_mut() }; let state = *this.inner.state.get_mut(); @@ -1342,7 +1321,7 @@ impl Lazy { /// /// This requires mutable access to self, so rust's aliasing rules prevent any concurrent /// access and allow violating the usual rules for accessing this cell. - pub fn try_get_mut_unpin(&mut self) -> Option<&mut T> { + pub fn try_get_mut_unpin(&mut self) -> Option<&mut F::Output> { let state = *self.inner.state.get_mut(); if state & READY_BIT == 0 { None @@ -1356,12 +1335,12 @@ impl Lazy { /// /// Similar to the try_get functions, this returns None if the future has not yet completed, /// even if the value would be available without blocking. - pub fn into_inner(self) -> Option { + pub fn into_inner(self) -> Option { self.into_parts().ok() } /// Takes ownership of the value or the initializing future. - pub fn into_parts(mut self) -> Result { + pub fn into_parts(mut self) -> Result { let state = *self.inner.state.get_mut(); // Safety: we can take ownership of the contents of self.value as long as we avoid dropping @@ -1387,9 +1366,9 @@ impl Lazy { /// /// This is equivalent to `mem::replace(self, replacement).into_inner()` but does not require /// that `F` be `Unpin` like that expression would. - pub fn replace_and_take(self: Pin<&mut Self>, replacement: Self) -> Option + pub fn replace_and_take(self: Pin<&mut Self>, replacement: Self) -> Option where - T: Unpin, + F::Output: Unpin, { // Safety: this reads fields and then open-codes Pin::set let this = unsafe { self.get_unchecked_mut() }; @@ -1405,7 +1384,7 @@ impl Lazy { } } -impl Drop for Lazy { +impl Drop for Lazy { fn drop(&mut self) { let state = *self.inner.state.get_mut(); // Safety: the state always reflects the variant of the union that we must drop @@ -1421,7 +1400,10 @@ impl Drop for Lazy { } } -impl fmt::Debug for Lazy { +impl fmt::Debug for Lazy +where + F::Output: fmt::Debug, +{ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { let value = self.try_get(); fmt.debug_struct("Lazy").field("value", &value).field("inner", &self.inner).finish()