#ifndef BEATRAT_RING_BUFFER_H
#define BEATRAT_RING_BUFFER_H

#include <stdatomic.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* Single-producer/single-consumer only. One thread pushes, one thread
 * pops -- never more than one of each at a time. */
typedef struct {
    int16_t *buf;
    size_t capacity;              /* number of int16_t elements */
    atomic_size_t head;           /* producer-owned */
    atomic_size_t tail;           /* consumer-owned */
    atomic_bool producer_finished; /* producer sets this when it has no more data coming */
} RingBuffer;

int  rb_init(RingBuffer *rb, size_t capacity);
void rb_free(RingBuffer *rb);

/* Producer-only. Returns the number of elements actually written --
 * may be less than count if the buffer doesn't have room; caller
 * should retry the remainder. */
size_t rb_push(RingBuffer *rb, const int16_t *data, size_t count);

/* Consumer-only. Returns the number of elements actually read -- may
 * be less than count if not enough data is available yet. */
size_t rb_pop(RingBuffer *rb, int16_t *data, size_t count);

size_t rb_available_to_read(const RingBuffer *rb);
size_t rb_available_to_write(const RingBuffer *rb);

#endif
