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

update the documentation

parent 09682676
No related branches found
No related tags found
No related merge requests found
//! `static` friendly data structures that don't require dynamic memory //! `static` friendly data structures that don't require dynamic memory
//! allocation //! allocation
#![deny(missing_docs)]
#![feature(const_fn)] #![feature(const_fn)]
#![feature(shared)] #![feature(shared)]
#![feature(unsize)] #![feature(unsize)]
...@@ -14,8 +15,6 @@ pub use ring_buffer::RingBuffer; ...@@ -14,8 +15,6 @@ pub use ring_buffer::RingBuffer;
pub mod ring_buffer; pub mod ring_buffer;
mod vec; mod vec;
/// Error /// Error raised when the buffer is full
#[derive(Clone, Copy, Debug, Eq, PartialEq)] #[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Error { pub struct BufferFullError;
Full,
}
//! Ring buffer
use core::marker::{PhantomData, Unsize}; use core::marker::{PhantomData, Unsize};
use core::ptr; use core::ptr;
use untagged_option::UntaggedOption; use untagged_option::UntaggedOption;
use Error; use BufferFullError;
pub use self::spsc::{Consumer, Producer}; pub use self::spsc::{Consumer, Producer};
mod spsc; mod spsc;
/// An statically allocated ring buffer backed by an array with type `A` /// An statically allocated ring buffer backed by an array `A`
pub struct RingBuffer<T, A> pub struct RingBuffer<T, A>
where where
// FIXME(rust-lang/rust#44580) use "const generics" instead of `Unsize` // FIXME(rust-lang/rust#44580) use "const generics" instead of `Unsize`
...@@ -38,11 +40,13 @@ where ...@@ -38,11 +40,13 @@ where
} }
} }
/// Returns the maximum number of elements the ring buffer can hold
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
let buffer: &[T] = unsafe { self.buffer.as_ref() }; let buffer: &[T] = unsafe { self.buffer.as_ref() };
buffer.len() - 1 buffer.len() - 1
} }
/// Returns the item in the front of the queue, or `None` if the queue is empty
pub fn dequeue(&mut self) -> Option<T> { pub fn dequeue(&mut self) -> Option<T> {
let n = self.capacity() + 1; let n = self.capacity() + 1;
let buffer: &[T] = unsafe { self.buffer.as_ref() }; let buffer: &[T] = unsafe { self.buffer.as_ref() };
...@@ -56,7 +60,10 @@ where ...@@ -56,7 +60,10 @@ where
} }
} }
pub fn enqueue(&mut self, item: T) -> Result<(), Error> { /// Adds an `item` to the end of the queue
///
/// Returns `BufferFullError` if the queue is full
pub fn enqueue(&mut self, item: T) -> Result<(), BufferFullError> {
let n = self.capacity() + 1; let n = self.capacity() + 1;
let buffer: &mut [T] = unsafe { self.buffer.as_mut() }; let buffer: &mut [T] = unsafe { self.buffer.as_mut() };
...@@ -68,10 +75,11 @@ where ...@@ -68,10 +75,11 @@ where
self.tail = next_tail; self.tail = next_tail;
Ok(()) Ok(())
} else { } else {
Err(Error::Full) Err(BufferFullError)
} }
} }
/// Returns the number of elements in the queue
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
if self.head > self.tail { if self.head > self.tail {
self.head - self.tail self.head - self.tail
...@@ -89,7 +97,7 @@ where ...@@ -89,7 +97,7 @@ where
} }
} }
/// Mutable version of `iter` /// Returns an iterator that allows modifying each value.
pub fn iter_mut(&mut self) -> IterMut<T, A> { pub fn iter_mut(&mut self) -> IterMut<T, A> {
let len = self.len(); let len = self.len();
IterMut { IterMut {
...@@ -137,6 +145,7 @@ where ...@@ -137,6 +145,7 @@ where
} }
} }
/// An iterator over a ring buffer items
pub struct Iter<'a, T, A> pub struct Iter<'a, T, A>
where where
A: Unsize<[T]> + 'a, A: Unsize<[T]> + 'a,
...@@ -147,6 +156,7 @@ where ...@@ -147,6 +156,7 @@ where
len: usize, len: usize,
} }
/// A mutable iterator over a ring buffer items
pub struct IterMut<'a, T, A> pub struct IterMut<'a, T, A>
where where
A: Unsize<[T]> + 'a, A: Unsize<[T]> + 'a,
......
use core::ptr::{self, Shared}; use core::ptr::{self, Shared};
use core::marker::Unsize; use core::marker::Unsize;
use Error; use BufferFullError;
use ring_buffer::RingBuffer; use ring_buffer::RingBuffer;
impl<T, A> RingBuffer<T, A> impl<T, A> RingBuffer<T, A>
...@@ -9,6 +9,9 @@ where ...@@ -9,6 +9,9 @@ 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
///
/// *Warning* the current implementation only supports single core processors. It's also fine to
/// use both end points on the same core of a multi-core processor.
pub fn split(&'static mut self) -> (Producer<T, A>, Consumer<T, A>) { pub fn split(&'static mut self) -> (Producer<T, A>, Consumer<T, A>) {
( (
Producer { Producer {
...@@ -35,13 +38,14 @@ impl<T, A> Consumer<T, A> ...@@ -35,13 +38,14 @@ impl<T, A> Consumer<T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
/// Returns the item in the front of the queue, or `None` if the queue is empty
pub fn dequeue(&mut self) -> Option<T> { pub fn dequeue(&mut self) -> Option<T> {
let rb = unsafe { self.rb.as_mut() }; let rb = unsafe { self.rb.as_mut() };
let n = rb.capacity() + 1; let n = rb.capacity() + 1;
let buffer: &[T] = unsafe { rb.buffer.as_ref() }; let buffer: &[T] = unsafe { rb.buffer.as_ref() };
// NOTE(volatile) the value of `tail` can change at any time in the context of the consumer // NOTE(volatile) the value of `tail` can change at any time in the execution context of the
// so we inform this to the compiler using a volatile load // consumer so we inform this to the compiler using a volatile load
if rb.head != unsafe { ptr::read_volatile(&rb.tail) } { if rb.head != unsafe { ptr::read_volatile(&rb.tail) } {
let item = unsafe { ptr::read(buffer.as_ptr().offset(rb.head as isize)) }; let item = unsafe { ptr::read(buffer.as_ptr().offset(rb.head as isize)) };
rb.head = (rb.head + 1) % n; rb.head = (rb.head + 1) % n;
...@@ -67,14 +71,17 @@ impl<T, A> Producer<T, A> ...@@ -67,14 +71,17 @@ impl<T, A> Producer<T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
pub fn enqueue(&mut self, item: T) -> Result<(), Error> { /// Adds an `item` to the end of the queue
///
/// Returns `BufferFullError` if the queue is full
pub fn enqueue(&mut self, item: T) -> Result<(), BufferFullError> {
let rb = unsafe { self.rb.as_mut() }; let rb = unsafe { self.rb.as_mut() };
let n = rb.capacity() + 1; let n = rb.capacity() + 1;
let buffer: &mut [T] = unsafe { rb.buffer.as_mut() }; let buffer: &mut [T] = unsafe { rb.buffer.as_mut() };
let next_tail = (rb.tail + 1) % n; let next_tail = (rb.tail + 1) % n;
// NOTE(volatile) the value of `head` can change at any time in the context of the producer // NOTE(volatile) the value of `head` can change at any time in the execution context of the
// so we inform this to the compiler using a volatile load // producer so we inform this to the compiler using a volatile load
if next_tail != unsafe { ptr::read_volatile(&rb.head) } { if next_tail != unsafe { ptr::read_volatile(&rb.head) } {
// NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We // NOTE(ptr::write) the memory slot that we are about to write to is uninitialized. We
// use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory // use `ptr::write` to avoid running `T`'s destructor on the uninitialized memory
...@@ -82,7 +89,7 @@ where ...@@ -82,7 +89,7 @@ where
rb.tail = next_tail; rb.tail = next_tail;
Ok(()) Ok(())
} else { } else {
Err(Error::Full) Err(BufferFullError)
} }
} }
} }
......
...@@ -3,9 +3,9 @@ use core::{ops, ptr, slice}; ...@@ -3,9 +3,9 @@ use core::{ops, ptr, slice};
use untagged_option::UntaggedOption; use untagged_option::UntaggedOption;
use Error; use BufferFullError;
/// [`Vec`] backed by a fixed size array /// A [`Vec`], *vector*, backed by a fixed size array
/// ///
/// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html /// [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
pub struct Vec<T, A> pub struct Vec<T, A>
...@@ -22,6 +22,7 @@ impl<T, A> Vec<T, A> ...@@ -22,6 +22,7 @@ impl<T, A> Vec<T, A>
where where
A: Unsize<[T]>, A: Unsize<[T]>,
{ {
/// Constructs a new, empty `Vec<T>` backed by the array `A`
pub const fn new() -> Self { pub const fn new() -> Self {
Vec { Vec {
_marker: PhantomData, _marker: PhantomData,
...@@ -30,19 +31,13 @@ where ...@@ -30,19 +31,13 @@ where
} }
} }
/// Returns the maximum number of elements the vector can hold
pub fn capacity(&self) -> usize { pub fn capacity(&self) -> usize {
let buffer: &[T] = unsafe { self.buffer.as_ref() }; let buffer: &[T] = unsafe { self.buffer.as_ref() };
buffer.len() buffer.len()
} }
pub fn iter(&self) -> slice::Iter<T> { /// Removes the last element from a vector and return it, or `None` if it's empty
(**self).iter()
}
pub fn iter_mut(&mut self) -> slice::IterMut<T> {
(**self).iter_mut()
}
pub fn pop(&mut self) -> Option<T> { pub fn pop(&mut self) -> Option<T> {
let buffer: &[T] = unsafe { self.buffer.as_ref() }; let buffer: &[T] = unsafe { self.buffer.as_ref() };
...@@ -55,7 +50,10 @@ where ...@@ -55,7 +50,10 @@ where
} }
} }
pub fn push(&mut self, item: T) -> Result<(), Error> { /// Appends an element to the back of the collection
///
/// Returns `BufferFullError` if the vector is full
pub fn push(&mut self, item: T) -> Result<(), BufferFullError> {
let capacity = self.capacity(); let capacity = self.capacity();
let buffer: &mut [T] = unsafe { self.buffer.as_mut() }; let buffer: &mut [T] = unsafe { self.buffer.as_mut() };
...@@ -66,7 +64,7 @@ where ...@@ -66,7 +64,7 @@ where
self.len += 1; self.len += 1;
Ok(()) Ok(())
} else { } else {
Err(Error::Full) Err(BufferFullError)
} }
} }
} }
...@@ -152,7 +150,6 @@ mod tests { ...@@ -152,7 +150,6 @@ mod tests {
static mut COUNT: i32 = 0; static mut COUNT: i32 = 0;
{ {
let mut v: Vec<Droppable, [Droppable; 2]> = Vec::new(); let mut v: Vec<Droppable, [Droppable; 2]> = Vec::new();
v.push(Droppable::new()).unwrap(); v.push(Droppable::new()).unwrap();
...@@ -231,5 +228,4 @@ mod tests { ...@@ -231,5 +228,4 @@ mod tests {
assert_eq!(v.pop(), None); assert_eq!(v.pop(), None);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment