From 89a64f8c3bdecb20a98e8edafe27cd5bd479bdae Mon Sep 17 00:00:00 2001 From: James Liu Date: Sat, 13 Apr 2024 09:01:26 -0700 Subject: [PATCH] feat: Make unbounded a const function This PR makes `ConcurrentQueue::unbounded` a const function. It'd be great if `bounded` could be `const` as well, but this would likely require static memory allocation support in const functions, which is currently not allowed by the compiler. This would enable https://github.com/smol-rs/async-executor/pull/112 to be directly constructable in a const context (i.e. static/thread_local variable initialization without OnceLock). It might also allow unbounded `async_channel`s to be constructed in a similar context. Co-authored-by: Taiki Endo --- src/lib.rs | 45 +++++++++++++++++++++++++++++++++------------ src/unbounded.rs | 28 ++++++++++++++++------------ 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8b495ce..a4d26b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,24 @@ mod unbounded; mod sync; +/// Make the given function const if the given condition is true. +macro_rules! const_fn { + ( + const_if: #[cfg($($cfg:tt)+)]; + $(#[$($attr:tt)*])* + $vis:vis const fn $($rest:tt)* + ) => { + #[cfg($($cfg)+)] + $(#[$($attr)*])* + $vis const fn $($rest)* + #[cfg(not($($cfg)+))] + $(#[$($attr)*])* + $vis fn $($rest)* + }; +} + +pub(crate) use const_fn; + /// A concurrent queue. /// /// # Examples @@ -131,18 +149,21 @@ impl ConcurrentQueue { } } - /// Creates a new unbounded queue. - /// - /// # Examples - /// - /// ``` - /// use concurrent_queue::ConcurrentQueue; - /// - /// let q = ConcurrentQueue::::unbounded(); - /// ``` - pub fn unbounded() -> ConcurrentQueue { - ConcurrentQueue(Inner::Unbounded(Unbounded::new())) - } + const_fn!( + const_if: #[cfg(not(loom))]; + /// Creates a new unbounded queue. + /// + /// # Examples + /// + /// ``` + /// use concurrent_queue::ConcurrentQueue; + /// + /// let q = ConcurrentQueue::::unbounded(); + /// ``` + pub const fn unbounded() -> ConcurrentQueue { + ConcurrentQueue(Inner::Unbounded(Unbounded::new())) + } + ); /// Attempts to push an item into the queue. /// diff --git a/src/unbounded.rs b/src/unbounded.rs index a84f856..8e1c40d 100644 --- a/src/unbounded.rs +++ b/src/unbounded.rs @@ -4,6 +4,7 @@ use core::ptr; use crossbeam_utils::CachePadded; +use crate::const_fn; use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use crate::sync::cell::UnsafeCell; #[allow(unused_imports)] @@ -148,19 +149,22 @@ pub struct Unbounded { } impl Unbounded { - /// Creates a new unbounded queue. - pub fn new() -> Unbounded { - Unbounded { - head: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), + const_fn!( + const_if: #[cfg(not(loom))]; + /// Creates a new unbounded queue. + pub const fn new() -> Unbounded { + Unbounded { + head: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + } } - } + ); /// Pushes an item into the queue. pub fn push(&self, value: T) -> Result<(), PushError> {