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:
parent
59e93fc952
commit
89a64f8c3b
45
src/lib.rs
45
src/lib.rs
|
@ -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.
|
||||||
///
|
///
|
||||||
|
|
|
@ -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>> {
|
||||||
|
|
Loading…
Reference in New Issue