Skip to content

Commit db0e134

Browse files
committed
Make Queue::split const.
1 parent 9a2e0af commit db0e134

File tree

4 files changed

+122
-2
lines changed

4 files changed

+122
-2
lines changed

CHANGELOG.md

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

1919
- Changed `stable_deref_trait` to a platform-dependent dependency.
20+
- Changed `Queue::split` to be `const` when `"nightly"` feature is enabled.
2021

2122
### Fixed
2223

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
@@ -77,6 +77,7 @@
7777
#![cfg_attr(not(test), no_std)]
7878
#![deny(missing_docs)]
7979
#![deny(warnings)]
80+
#![cfg_attr(feature = "nightly", feature(const_mut_refs))]
8081

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

src/spsc.rs

+116-2
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,95 @@ 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::{Queue, Producer};
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+
/// }.get_or_insert_with(|| {
345+
/// critical_section::with(|cs| {
346+
/// PRODUCER.borrow_ref_mut(cs).take().unwrap()
347+
/// })
348+
/// });
349+
/// }
350+
/// ```
351+
#[cfg(not(feature = "nightly"))]
309352
pub fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
310353
(Producer { rb: self }, Consumer { rb: self })
311354
}
355+
356+
/// Splits a queue into producer and consumer endpoints.
357+
///
358+
/// # Examples
359+
///
360+
/// ```
361+
/// #![feature(const_mut_refs)]
362+
///
363+
/// use core::cell::RefCell;
364+
///
365+
/// use critical_section::Mutex;
366+
/// use heapless::spsc::{Queue, Producer, Consumer};
367+
///
368+
/// static PC: Mutex<RefCell<(Option<Producer<'static, (), 4>>, Option<Consumer<'static, (), 4>>)>> = {
369+
/// static mut Q: Queue<(), 4> = Queue::new();
370+
/// let (p, c) = unsafe { Q.split() };
371+
/// Mutex::new(RefCell::new((Some(p), Some(c))))
372+
/// };
373+
///
374+
/// fn main() {
375+
/// let mut consumer = critical_section::with(|cs| {
376+
/// (*PC.borrow_ref_mut(cs)).1.take().unwrap()
377+
/// });
378+
/// }
379+
///
380+
/// fn interrupt() {
381+
/// let mut producer = {
382+
/// static mut P: Option<Producer<'static, (), 4>> = None;
383+
/// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
384+
/// // and `interrupt` cannot be called directly or preempt itself.
385+
/// unsafe { &mut P }
386+
/// }.get_or_insert_with(|| {
387+
/// critical_section::with(|cs| {
388+
/// (*PC.borrow_ref_mut(cs)).0.take().unwrap()
389+
/// })
390+
/// });
391+
/// }
392+
/// ```
393+
#[cfg(feature = "nightly")]
394+
pub const fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
395+
(Producer { rb: self }, Consumer { rb: self })
396+
}
312397
}
313398

314399
impl<T, const N: usize> Default for Queue<T, N> {
@@ -632,7 +717,36 @@ impl<'a, T, const N: usize> Producer<'a, T, N> {
632717
mod tests {
633718
use std::hash::{Hash, Hasher};
634719

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

637751
#[test]
638752
fn full() {

0 commit comments

Comments
 (0)