Skip to content

Commit bcf76a5

Browse files
committed
Make Queue::split const.
1 parent c593fa5 commit bcf76a5

File tree

4 files changed

+123
-2
lines changed

4 files changed

+123
-2
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
2121
### Changed
2222

2323
- Changed `stable_deref_trait` to a platform-dependent dependency.
24+
- Changed `Queue::split` to be `const` when `"nightly"` feature is enabled.
2425

2526
### Fixed
2627

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ defmt-03 = ["dep:defmt"]
3939
# Enable larger MPMC sizes.
4040
mpmc_large = []
4141

42+
# Enable nightly features.
43+
nightly = []
44+
4245
[dependencies]
4346
portable-atomic = { version = "1.0", optional = true }
4447
hash32 = "0.3.0"
@@ -51,6 +54,7 @@ defmt = { version = ">=0.2.0,<0.4", optional = true }
5154
stable_deref_trait = { version = "1", default-features = false }
5255

5356
[dev-dependencies]
57+
critical-section = { version = "1.1", features = ["std"] }
5458
ufmt = "0.2"
5559

5660
[package.metadata.docs.rs]

src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
#![cfg_attr(docsrs, feature(doc_cfg), feature(doc_auto_cfg))]
7777
#![cfg_attr(not(test), no_std)]
7878
#![deny(missing_docs)]
79+
#![cfg_attr(feature = "nightly", feature(const_mut_refs))]
7980

8081
pub use binary_heap::BinaryHeap;
8182
pub use deque::Deque;

src/spsc.rs

+117-2
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,96 @@ impl<T, const N: usize> Queue<T, N> {
305305
self.inner_dequeue_unchecked()
306306
}
307307

308-
/// Splits a queue into producer and consumer endpoints
308+
/// Splits a queue into producer and consumer endpoints.
309+
///
310+
/// # Examples
311+
///
312+
/// ```
313+
/// use core::cell::RefCell;
314+
/// use critical_section::Mutex;
315+
/// use heapless::spsc::{Producer, Queue};
316+
///
317+
/// static PRODUCER: Mutex<RefCell<Option<Producer<'static, (), 4>>>> =
318+
/// Mutex::new(RefCell::new(None));
319+
///
320+
/// fn main() {
321+
/// let mut consumer = {
322+
/// let (p, c) = {
323+
/// static mut Q: Queue<(), 4> = Queue::new();
324+
/// // SAFETY: Mutable access to `Q` is allowed exclusively in this scope
325+
/// // and `main` is only called once.
326+
/// unsafe { Q.split() }
327+
/// };
328+
///
329+
/// critical_section::with(move |cs| {
330+
/// let mut producer = PRODUCER.borrow_ref_mut(cs);
331+
/// *producer = Some(p);
332+
/// });
333+
///
334+
/// c
335+
/// };
336+
/// }
337+
///
338+
/// fn interrupt() {
339+
/// let mut producer = {
340+
/// static mut P: Option<Producer<'static, (), 4>> = None;
341+
/// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
342+
/// // and `interrupt` cannot be called directly or preempt itself.
343+
/// unsafe { &mut P }
344+
/// }
345+
/// .get_or_insert_with(|| {
346+
/// critical_section::with(|cs| PRODUCER.borrow_ref_mut(cs).take().unwrap())
347+
/// });
348+
/// }
349+
/// ```
350+
#[cfg(not(feature = "nightly"))]
309351
pub fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
310352
(Producer { rb: self }, Consumer { rb: self })
311353
}
354+
355+
/// Splits a queue into producer and consumer endpoints.
356+
///
357+
/// # Examples
358+
///
359+
/// ```
360+
/// #![feature(const_mut_refs)]
361+
///
362+
/// use core::cell::RefCell;
363+
///
364+
/// use critical_section::Mutex;
365+
/// use heapless::spsc::{Consumer, Producer, Queue};
366+
///
367+
/// static PC: Mutex<
368+
/// RefCell<(
369+
/// Option<Producer<'static, (), 4>>,
370+
/// Option<Consumer<'static, (), 4>>,
371+
/// )>,
372+
/// > = {
373+
/// static mut Q: Queue<(), 4> = Queue::new();
374+
/// let (p, c) = unsafe { Q.split() };
375+
/// Mutex::new(RefCell::new((Some(p), Some(c))))
376+
/// };
377+
///
378+
/// fn main() {
379+
/// let mut consumer = critical_section::with(|cs| (*PC.borrow_ref_mut(cs)).1.take().unwrap());
380+
/// }
381+
///
382+
/// fn interrupt() {
383+
/// let mut producer = {
384+
/// static mut P: Option<Producer<'static, (), 4>> = None;
385+
/// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
386+
/// // and `interrupt` cannot be called directly or preempt itself.
387+
/// unsafe { &mut P }
388+
/// }
389+
/// .get_or_insert_with(|| {
390+
/// critical_section::with(|cs| (*PC.borrow_ref_mut(cs)).0.take().unwrap())
391+
/// });
392+
/// }
393+
/// ```
394+
#[cfg(feature = "nightly")]
395+
pub const fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
396+
(Producer { rb: self }, Consumer { rb: self })
397+
}
312398
}
313399

314400
impl<T, const N: usize> Default for Queue<T, N> {
@@ -632,7 +718,36 @@ impl<'a, T, const N: usize> Producer<'a, T, N> {
632718
mod tests {
633719
use std::hash::{Hash, Hasher};
634720

635-
use crate::spsc::Queue;
721+
use super::Queue;
722+
723+
#[cfg(feature = "nightly")]
724+
#[test]
725+
fn const_split() {
726+
use critical_section::Mutex;
727+
use std::cell::RefCell;
728+
729+
static PC: Mutex<
730+
RefCell<(
731+
Option<Producer<'static, (), 4>>,
732+
Option<Consumer<'static, (), 4>>,
733+
)>,
734+
> = {
735+
static mut Q: Queue<(), 4> = Queue::new();
736+
let (p, c) = unsafe { Q.split() };
737+
Mutex::new(RefCell::new((Some(p), Some(c))))
738+
};
739+
740+
let (producer, consumer) = critical_section::with(|cs| {
741+
let mut pc = PC.borrow_ref_mut(cs);
742+
(pc.0.take().unwrap(), pc.1.take().unwrap())
743+
});
744+
745+
let mut producer: Producer<'static, (), 4> = producer;
746+
let mut consumer: Consumer<'static, (), 4> = consumer;
747+
748+
assert_eq!(producer.enqueue(()), Ok(()));
749+
assert_eq!(consumer.dequeue(), Some(()));
750+
}
636751

637752
#[test]
638753
fn full() {

0 commit comments

Comments
 (0)