spsc-ringbuf-core 0.1.0

Heapless ring buffer
Documentation
# Introduction

This is a heapless single producer single consumer (SPSC) ring buffer that
depends only on the Rust Core library. The implementation consists of an inner
ring buffer and a lightweight wrapper for providing a pair of mutable access
handlers that can be moved to their corresponding producer and consumer
entities. The inner ring buffer is designed to be easily instantiable as global
static encapsulating any need of using `unsafe` to access the structure in user
code.

# Basic ring buffer

The underlying ring buffer utilizes the "Array + two unmasked indices" method
illustrated
[here](https://www.snellman.net/blog/archive/2016-12-13-ring-buffers/).
Essentially this allows usage of all elements allocated in the buffer without
resorting to storing length along with read and write indices. If the Const
Generics parameter capacity `N` is power of two, the overhead of masking read
and write indices (within `[0, N-1]`) is only required upon buffer access.
If `N` is not a power of two, the implementation wraps the indices between `0`
and `2*N-1` as they are incremented. 

The maximum supported size of buffer is `2^32 - 1` items. This limit comes from
the size of the read and write indices (`u32`). This can be relaxed if needed
by changing the index to `usize` type.

The ring buffer item is a generic structure with no trait requirements.

## Usage model

The producer calls `write_front()` to beginning writing to the location under
`buffer[mask(wr_idx)]`. This returns a mutable reference to the underlying
item. After the location is populated, the producer calls `commit()` to advance
the write index. The consumer can use `read_front()` to check (and read) new
items available. The consumer uses `pop()` to consume the item and advance the
read index.

# Working around limitations of static global

In order to achieve the goal of allocating these queues statically while avoid
requiring all code that uses the structure to be wrapped in `unsafe`, the
implementation employs the following methods:

1. `Cell` wrapped read and write indices for providing interior mutability of
   indices
2. limited internal `unsafe` code to return mutable references of the inner
   buffer. This is considered safe due to the single producer and single
   consumer premise. i.e. write index is only modified by the producer and read
   index only modified by the consumer.
3. Use of `MaybeUninit` in inner buffer to avoid static initialization (not
   required in queues)
4. `Cell` structures are not inheritently thread safe and globals containing
   Cells cannot be instantiated for the lack of the `Sync` trait marker. Again
   due to the SPSC premise, the `core::marker::Sync` is added to the `RingbufRef`
   structure. Straightly speaking though, the marker should be *only* added to
   wrapper `Ringbuf` structure which enforces SPSC use with the `split`
   operation. But this is not done to allow instantianting global `RingbufRef`
   without incurring the handler overhead should the user decides the usage is
   safe enouhg.

# Top level wrapper

The top level `RingBuf` structure provides the final protection of unintended
direct usage of the inner ring buffer. This wrapper provides a one-time call
returning a pair of (mutable) handles that can be moved to producer and
consumer entities. Since the `writ_front`, `commit` and `pop` functions all
require mutable `self`, Rust's single mutable reference check should guarantee
that only a single producer or consumer is possible.

# Shared Singleton

This crate also provides a separate cheaper implementation for the special case
of single item ring buffer. In this version a tri-state `owner` flag replaces
all read and write indices manipulation overhead. This structure can also be
used in conjunction with the ring buffer to serve as ringbuffer data
extension. In a heapless environment, for example, one can imagine with dynamic
allocation it would be difficult to create a command queue with a deeper depth
than available command "payloads" since not all commands require a payload. 

In the included `SharedPool` example, payload can be allocated from a pool of
such shared singletons with pool index passed by command in the queue. The
`owner` flag provides separate ownership tracking of each item in the payload
pool. On initialization, the return ring buffer is filled to indicate that
every pool item belongs to the allocation producer. Producer allocates an item
in the pool and pass the index along with any other information through the
`alloc_prod` ring buffer. As the consumer is done with the allocated item, it
is returned (in the form of the pool index) through the return ring buffer.

```
                        Pool of SharedSingleton<T>
                        ┌─┬─┬─┬─┐   ┌───┐
                        │0│1│2│3│ ..│N-1│
                        └─┴─┴─┴┬┘   └───┘
┌────────────────┐             │PoolIndex<N>       ┌────────────────┐
│Producer        │         ┌───┘                   │Consumer        │
│ ┌───────────┐  │         │                       │ ┌───────────┐  │
│ │alloc_prod ├──┼───┐  ┌─┬┴┬─┬─┬─┐   ┌───┐     ┌──► │alloc_cons │  │
│ └───────────┘  │   └─►│0│1│2│3│4│.. │M-1├─────┘  │ └───────────┘  │
│  RingbufProducer      └─┴─┴─┴─┴─┘   └───┘        │                │
│ ┌───────────┐  │   Prod. -> Cons Ringbuf<Q,M>    │ ┌───────────┐  │
│ │return_cons│◄─┼──┐                            ┌─┼─┤return_prod│  │
│ └───────────┘  │  │   ┌─┬─┬─┬─┬─┐   ┌───┐      │ │ └───────────┘  │
│ RingbufConsumer│  └───┤0│1│2│3│4│.. │M-1│◄─────┘ │                │
└────────────────┘      └─┴─┴─┴─┴─┘   └───┘        └────────────────┘
                    Cons. -> Prod. Ringbuf<Q,M>


```