# Rolling stream

The unit at [io/roll.fs] implements a rolling stream [io/stream], that is, a
static buffer with a read and write pointer. When a pointer reaches the end of
the buffer, it rolls over to the beginning.

When both pointers are equal, the buffer is empty, when the write pointer is one
less than the read pointer, the buffer is full.

This might sound similar to [mem/scratch], but unlike it, this buffer doesn't
blissfully overwrite contents. When it's full, it refuses writing.

This buffer is designed to be fast and accomodate the needs for shoveling bytes
around when handling IRQs [doc/intr].

## Reading buffer lifetime

When reading from the buffer, you'll need a little bit of time to process that
memory range you're given before further IRQs write over it. For this reason,
the memory that a readbuf call frees isn't actually freed until the *next* call,
therefore giving the caller the time to copy it elsewhere.

This is what the "nextridx" field is for.

## Example usage

needs io/roll
$100 const BUFSZ
BUFSZ newrollingbuffer const mybuf
"hello" mybuf puts \ works like any stream

## API

### Structures

extends Stream struct RollBuf {
  uint ridx widx nextridx bufsz ;
  [void,0] buffer ;
}

### Words

newrollingbuffer ( bufsz -- rollbuf )
  Allocates a new rolling stream of the specified size in bytes.

fastputc, ( -- fullbr )
  Compiles a fast equivalent to "putc". The runtime code has this signature:

  IN: A=rollbuf W=c  OUT: A=rollbuf CLOBBERED: W S

  The compile time word yields a branch to the case where the buffer is full.
  Example usage:

    fastputc,
      \ code handling the regular case
    else
      \ code handling the "full" error
    then
