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 <te316e89@gmail.com>
This commit is contained in:
James Liu 2024-04-13 09:01:26 -07:00 committed by GitHub
parent 59e93fc952
commit 89a64f8c3b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 49 additions and 24 deletions

View File

@ -75,6 +75,24 @@ mod unbounded;
mod sync; 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. /// A concurrent queue.
/// ///
/// # Examples /// # Examples
@ -131,18 +149,21 @@ impl<T> ConcurrentQueue<T> {
} }
} }
/// Creates a new unbounded queue. const_fn!(
/// const_if: #[cfg(not(loom))];
/// # Examples /// Creates a new unbounded queue.
/// ///
/// ``` /// # Examples
/// use concurrent_queue::ConcurrentQueue; ///
/// /// ```
/// let q = ConcurrentQueue::<i32>::unbounded(); /// use concurrent_queue::ConcurrentQueue;
/// ``` ///
pub fn unbounded() -> ConcurrentQueue<T> { /// let q = ConcurrentQueue::<i32>::unbounded();
ConcurrentQueue(Inner::Unbounded(Unbounded::new())) /// ```
} pub const fn unbounded() -> ConcurrentQueue<T> {
ConcurrentQueue(Inner::Unbounded(Unbounded::new()))
}
);
/// Attempts to push an item into the queue. /// Attempts to push an item into the queue.
/// ///

View File

@ -4,6 +4,7 @@ use core::ptr;
use crossbeam_utils::CachePadded; use crossbeam_utils::CachePadded;
use crate::const_fn;
use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering}; use crate::sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
use crate::sync::cell::UnsafeCell; use crate::sync::cell::UnsafeCell;
#[allow(unused_imports)] #[allow(unused_imports)]
@ -148,19 +149,22 @@ pub struct Unbounded<T> {
} }
impl<T> Unbounded<T> { impl<T> Unbounded<T> {
/// Creates a new unbounded queue. const_fn!(
pub fn new() -> Unbounded<T> { const_if: #[cfg(not(loom))];
Unbounded { /// Creates a new unbounded queue.
head: CachePadded::new(Position { pub const fn new() -> Unbounded<T> {
block: AtomicPtr::new(ptr::null_mut()), Unbounded {
index: AtomicUsize::new(0), head: CachePadded::new(Position {
}), block: AtomicPtr::new(ptr::null_mut()),
tail: CachePadded::new(Position { index: AtomicUsize::new(0),
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. /// Pushes an item into the queue.
pub fn push(&self, value: T) -> Result<(), PushError<T>> { pub fn push(&self, value: T) -> Result<(), PushError<T>> {