Skip to content
Snippets Groups Projects
Commit 30ea33c3 authored by Jorge Aparicio's avatar Jorge Aparicio
Browse files

relax the lifetime constraint of RingBuffer.split

also

- add a "`split` freezes the ring buffer" compile fail test
- hide compile-fail doc tests
- add scoped threads tests
parent 731e8ae1
No related branches found
No related tags found
No related merge requests found
...@@ -17,3 +17,6 @@ version = "0.2.0" ...@@ -17,3 +17,6 @@ version = "0.2.0"
[dependencies] [dependencies]
untagged-option = "0.1.1" untagged-option = "0.1.1"
[dev-dependencies]
scoped_threadpool = "0.1.8"
# false positives from thread::spawn (?) # false positives in thread::spawn (?)
race:*dealloc race:*dealloc
race:*drop_slow* race:*drop_slow*
race:__call_tls_dtors race:__call_tls_dtors
# false positives in scoped_threadpool (?)
race:*drop*
//! Compile fail tests
//!
//! # `Send`-ness
//!
//! Collections of `Send`-able things are `Send`
//!
//! ```
//! use heapless::{RingBuffer, Vec};
//! use heapless::ring_buffer::{Consumer, Producer};
//!
//! struct IsSend;
//!
//! unsafe impl Send for IsSend {}
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Consumer<IsSend, [IsSend; 4]>>();
//! is_send::<Producer<IsSend, [IsSend; 4]>>();
//! is_send::<RingBuffer<IsSend, [IsSend; 4]>>();
//! is_send::<Vec<IsSend, [IsSend; 4]>>();
//! ```
//!
//! Collections of non-`Send`-able things are *not* `Send`
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::ring_buffer::Consumer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Consumer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::ring_buffer::Producer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Producer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::RingBuffer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<RingBuffer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::Vec;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Vec<NotSend, [NotSend; 4]>>();
//! ```
//!
//! # Freeze
//!
//! Splitting a `RingBuffer` should invalidate the original reference.
//!
//! ``` compile_fail
//! use heapless::RingBuffer;
//!
//! let mut rb: RingBuffer<u8, [u8; 4]> = RingBuffer::new();
//!
//! let (p, c) = rb.split();
//! rb.enqueue(0).unwrap();
//! ```
...@@ -36,8 +36,6 @@ ...@@ -36,8 +36,6 @@
//! //!
//! ### Single producer single consumer mode //! ### Single producer single consumer mode
//! //!
//! For use in *single core* systems like microcontrollers
//!
//! ``` //! ```
//! use heapless::RingBuffer; //! use heapless::RingBuffer;
//! //!
...@@ -77,72 +75,6 @@ ...@@ -77,72 +75,6 @@
//! // .. //! // ..
//! } //! }
//! ``` //! ```
//!
//! # `Send`-ness
//!
//! Collections of `Send`-able things are `Send`
//!
//! ```
//! use heapless::{RingBuffer, Vec};
//! use heapless::ring_buffer::{Consumer, Producer};
//!
//! struct IsSend;
//!
//! unsafe impl Send for IsSend {}
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Consumer<IsSend, [IsSend; 4]>>();
//! is_send::<Producer<IsSend, [IsSend; 4]>>();
//! is_send::<RingBuffer<IsSend, [IsSend; 4]>>();
//! is_send::<Vec<IsSend, [IsSend; 4]>>();
//! ```
//!
//! Collections of not `Send`-able things are *not* `Send`
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::ring_buffer::Consumer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Consumer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::ring_buffer::Producer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Producer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::RingBuffer;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<RingBuffer<NotSend, [NotSend; 4]>>();
//! ```
//!
//! ``` compile_fail
//! use std::marker::PhantomData;
//! use heapless::Vec;
//!
//! type NotSend = PhantomData<*const ()>;
//!
//! fn is_send<T>() where T: Send {}
//!
//! is_send::<Vec<NotSend, [NotSend; 4]>>();
//! ```
#![deny(missing_docs)] #![deny(missing_docs)]
#![feature(const_fn)] #![feature(const_fn)]
...@@ -157,8 +89,9 @@ extern crate untagged_option; ...@@ -157,8 +89,9 @@ extern crate untagged_option;
pub use vec::Vec; pub use vec::Vec;
pub use ring_buffer::RingBuffer; pub use ring_buffer::RingBuffer;
pub mod ring_buffer; mod cfail;
mod vec; mod vec;
pub mod ring_buffer;
/// Error raised when the buffer is full /// Error raised when the buffer is full
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
......
use core::ptr::{self, Shared}; use core::ptr::{self, Shared};
use core::marker::Unsize; use core::marker::{PhantomData, Unsize};
use BufferFullError; use BufferFullError;
use ring_buffer::RingBuffer; use ring_buffer::RingBuffer;
...@@ -9,13 +9,15 @@ where ...@@ -9,13 +9,15 @@ where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
/// Splits a statically allocated ring buffer into producer and consumer end points /// Splits a statically allocated ring buffer into producer and consumer end points
pub fn split(&'static mut self) -> (Producer<T, A>, Consumer<T, A>) { pub fn split(&mut self) -> (Producer<T, A>, Consumer<T, A>) {
( (
Producer { Producer {
rb: unsafe { Shared::new_unchecked(self) }, rb: unsafe { Shared::new_unchecked(self) },
_marker: PhantomData,
}, },
Consumer { Consumer {
rb: unsafe { Shared::new_unchecked(self) }, rb: unsafe { Shared::new_unchecked(self) },
_marker: PhantomData,
}, },
) )
} }
...@@ -23,15 +25,16 @@ where ...@@ -23,15 +25,16 @@ where
/// A ring buffer "consumer"; it can dequeue items from the ring buffer /// A ring buffer "consumer"; it can dequeue items from the ring buffer
// NOTE the consumer semantically owns the `head` pointer of the ring buffer // NOTE the consumer semantically owns the `head` pointer of the ring buffer
pub struct Consumer<T, A> pub struct Consumer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
// XXX do we need to use `Shared` (for soundness) here? // XXX do we need to use `Shared` (for soundness) here?
rb: Shared<RingBuffer<T, A>>, rb: Shared<RingBuffer<T, A>>,
_marker: PhantomData<&'a ()>,
} }
impl<T, A> Consumer<T, A> impl<'a, T, A> Consumer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
...@@ -54,7 +57,7 @@ where ...@@ -54,7 +57,7 @@ where
} }
} }
unsafe impl<T, A> Send for Consumer<T, A> unsafe impl<'a, T, A> Send for Consumer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
T: Send, T: Send,
...@@ -63,15 +66,16 @@ where ...@@ -63,15 +66,16 @@ where
/// A ring buffer "producer"; it can enqueue items into the ring buffer /// A ring buffer "producer"; it can enqueue items into the ring buffer
// NOTE the producer semantically owns the `tail` pointer of the ring buffer // NOTE the producer semantically owns the `tail` pointer of the ring buffer
pub struct Producer<T, A> pub struct Producer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
// XXX do we need to use `Shared` (for soundness) here? // XXX do we need to use `Shared` (for soundness) here?
rb: Shared<RingBuffer<T, A>>, rb: Shared<RingBuffer<T, A>>,
_marker: PhantomData<&'a ()>,
} }
impl<T, A> Producer<T, A> impl<'a, T, A> Producer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
...@@ -99,7 +103,7 @@ where ...@@ -99,7 +103,7 @@ where
} }
} }
unsafe impl<T, A> Send for Producer<T, A> unsafe impl<'a, T, A> Send for Producer<'a, T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
T: Send, T: Send,
......
#![deny(warnings)] #![deny(warnings)]
extern crate heapless; extern crate heapless;
extern crate scoped_threadpool;
use std::thread; use std::thread;
use heapless::RingBuffer; use heapless::RingBuffer;
use scoped_threadpool::Pool;
#[test] #[test]
fn once() { fn once() {
...@@ -48,3 +50,26 @@ fn twice() { ...@@ -48,3 +50,26 @@ fn twice() {
c.dequeue().unwrap(); c.dequeue().unwrap();
}); });
} }
#[test]
fn scoped() {
let mut rb: RingBuffer<i32, [i32; 4]> = RingBuffer::new();
rb.enqueue(0).unwrap();
{
let (mut p, mut c) = rb.split();
Pool::new(2).scoped(move |scope| {
scope.execute(move || {
p.enqueue(1).unwrap();
});
scope.execute(move || {
c.dequeue().unwrap();
});
});
}
rb.dequeue().unwrap();
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment