From 5b74dc8acca8b915af29d12ae0a43bde15c5df97 Mon Sep 17 00:00:00 2001
From: John Nunley <dev@notgull.net>
Date: Thu, 25 Apr 2024 22:53:55 -0700
Subject: [PATCH] Merge fetch_and andthe prev_value check

cc https://github.com/smol-rs/concurrent-queue/pull/58#discussion_r1574686897

Signed-off-by: John Nunley <dev@notgull.net>
---
 src/single.rs | 28 ++++++++++++++++------------
 1 file changed, 16 insertions(+), 12 deletions(-)

diff --git a/src/single.rs b/src/single.rs
index 048f486..f88c478 100644
--- a/src/single.rs
+++ b/src/single.rs
@@ -65,23 +65,27 @@ impl<T> Single<T> {
             }
 
             if prev == state {
-                // Swap out the value.
-                // SAFETY: We have locked the state.
-                let prev_value = unsafe {
-                    self.slot
-                        .with_mut(move |slot| ptr::replace(slot, MaybeUninit::new(value)))
-                };
-
-                // We can unlock the slot now.
-                self.state.fetch_and(!LOCKED, Ordering::Release);
-
-                // If the value was pushed, initialize it and return it.
+                // If the value was pushed, swap out the value.
                 let prev_value = if prev & PUSHED == 0 {
+                    // SAFETY: write is safe because we have locked the state.
+                    self.slot.with_mut(|slot| unsafe {
+                        slot.write(MaybeUninit::new(value));
+                    });
                     None
                 } else {
-                    Some(unsafe { prev_value.assume_init() })
+                    // SAFETY: replace is safe because we have locked the state, and
+                    // assume_init is safe because we have checked that the value was pushed.
+                    let prev_value = unsafe {
+                        self.slot.with_mut(move |slot| {
+                            ptr::replace(slot, MaybeUninit::new(value)).assume_init()
+                        })
+                    };
+                    Some(prev_value)
                 };
 
+                // We can unlock the slot now.
+                self.state.fetch_and(!LOCKED, Ordering::Release);
+
                 // Return the old value.
                 return Ok(prev_value);
             }