Skip to content

Commit b643e9f

Browse files
committed
Make Queue::split const.
1 parent 6cd26cc commit b643e9f

File tree

4 files changed

+138
-1
lines changed

4 files changed

+138
-1
lines changed

CHANGELOG.md

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

2424
- Changed `stable_deref_trait` to a platform-dependent dependency.
25+
- Changed `Queue::split` to be `const` when `"nightly"` feature is enabled.
2526

2627
### Fixed
2728

Cargo.toml

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

42+
# Enable nightly features.
4243
nightly = []
4344

4445
[dependencies]
@@ -53,6 +54,7 @@ defmt = { version = ">=0.2.0,<0.4", optional = true }
5354
stable_deref_trait = { version = "1", default-features = false }
5455

5556
[dev-dependencies]
57+
critical-section = { version = "1.1", features = ["std"] }
5658
ufmt = "0.2"
5759
static_assertions = "1.1.0"
5860

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
#![cfg_attr(
8081
all(
8182
feature = "nightly",

src/spsc.rs

+134-1
Original file line numberDiff line numberDiff line change
@@ -305,10 +305,113 @@ 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 interrupt() {
321+
/// let mut producer = {
322+
/// static mut P: Option<Producer<'static, (), 4>> = None;
323+
/// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
324+
/// // and `interrupt` cannot be called directly or preempt itself.
325+
/// unsafe { &mut P }
326+
/// }
327+
/// .get_or_insert_with(|| {
328+
/// critical_section::with(|cs| PRODUCER.borrow_ref_mut(cs).take().unwrap())
329+
/// });
330+
///
331+
/// producer.enqueue(()).unwrap();
332+
/// }
333+
///
334+
/// fn main() {
335+
/// let mut consumer = {
336+
/// let (p, c) = {
337+
/// static mut Q: Queue<(), 4> = Queue::new();
338+
/// // SAFETY: Mutable access to `Q` is allowed exclusively in this scope
339+
/// // and `main` is only called once.
340+
/// unsafe { Q.split() }
341+
/// };
342+
///
343+
/// critical_section::with(move |cs| {
344+
/// let mut producer = PRODUCER.borrow_ref_mut(cs);
345+
/// *producer = Some(p);
346+
/// });
347+
///
348+
/// c
349+
/// };
350+
///
351+
/// // Interrupt occurs.
352+
/// # interrupt();
353+
///
354+
/// consumer.dequeue().unwrap();
355+
/// }
356+
/// ```
357+
#[cfg(not(feature = "nightly"))]
309358
pub fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
310359
(Producer { rb: self }, Consumer { rb: self })
311360
}
361+
362+
/// Splits a queue into producer and consumer endpoints.
363+
///
364+
/// # Examples
365+
///
366+
/// ```
367+
/// #![feature(const_mut_refs)]
368+
///
369+
/// use core::cell::RefCell;
370+
///
371+
/// use critical_section::Mutex;
372+
/// use heapless::spsc::{Consumer, Producer, Queue};
373+
///
374+
/// static PC: (
375+
/// Mutex<RefCell<Option<Producer<'_, (), 4>>>>,
376+
/// Mutex<RefCell<Option<Consumer<'_, (), 4>>>>,
377+
/// ) = {
378+
/// static mut Q: Queue<(), 4> = Queue::new();
379+
/// // SAFETY: Mutable access to `Q` is allowed exclusively in this scope.
380+
/// let (p, c) = unsafe { Q.split() };
381+
///
382+
/// (
383+
/// Mutex::new(RefCell::new(Some(p))),
384+
/// Mutex::new(RefCell::new(Some(c))),
385+
/// )
386+
/// };
387+
///
388+
/// fn interrupt() {
389+
/// let mut producer = {
390+
/// static mut P: Option<Producer<'_, (), 4>> = None;
391+
/// // SAFETY: Mutable access to `P` is allowed exclusively in this scope
392+
/// // and `interrupt` cannot be called directly or preempt itself.
393+
/// unsafe { &mut P }
394+
/// }
395+
/// .get_or_insert_with(|| {
396+
/// critical_section::with(|cs| PC.0.borrow_ref_mut(cs).take().unwrap())
397+
/// });
398+
///
399+
/// producer.enqueue(()).unwrap();
400+
/// }
401+
///
402+
/// fn main() {
403+
/// let mut consumer = critical_section::with(|cs| PC.1.borrow_ref_mut(cs).take().unwrap());
404+
///
405+
/// // Interrupt occurs.
406+
/// # interrupt();
407+
///
408+
/// consumer.dequeue().unwrap();
409+
/// }
410+
/// ```
411+
#[cfg(feature = "nightly")]
412+
pub const fn split(&mut self) -> (Producer<'_, T, N>, Consumer<'_, T, N>) {
413+
(Producer { rb: self }, Consumer { rb: self })
414+
}
312415
}
313416

314417
impl<T, const N: usize> Default for Queue<T, N> {
@@ -645,6 +748,36 @@ mod tests {
645748
// Ensure a `Consumer` containing `!Send` values stays `!Send` itself.
646749
assert_not_impl_any!(Consumer<*const (), 4>: Send);
647750

751+
#[cfg(feature = "nightly")]
752+
#[test]
753+
fn const_split() {
754+
use critical_section::Mutex;
755+
use std::cell::RefCell;
756+
757+
use super::{Consumer, Producer};
758+
759+
static PC: (
760+
Mutex<RefCell<Option<Producer<'_, (), 4>>>>,
761+
Mutex<RefCell<Option<Consumer<'_, (), 4>>>>,
762+
) = {
763+
static mut Q: Queue<(), 4> = Queue::new();
764+
let (p, c) = unsafe { Q.split() };
765+
766+
(
767+
Mutex::new(RefCell::new(Some(p))),
768+
Mutex::new(RefCell::new(Some(c))),
769+
)
770+
};
771+
let producer = critical_section::with(|cs| PC.0.borrow_ref_mut(cs).take().unwrap());
772+
let consumer = critical_section::with(|cs| PC.1.borrow_ref_mut(cs).take().unwrap());
773+
774+
let mut producer: Producer<'static, (), 4> = producer;
775+
let mut consumer: Consumer<'static, (), 4> = consumer;
776+
777+
assert_eq!(producer.enqueue(()), Ok(()));
778+
assert_eq!(consumer.dequeue(), Some(()));
779+
}
780+
648781
#[test]
649782
fn full() {
650783
let mut rb: Queue<i32, 3> = Queue::new();

0 commit comments

Comments
 (0)