use jack_sys as j;
use std::mem;
use std::sync::atomic::{AtomicBool, Ordering};
pub struct RingBuffer(*mut j::jack_ringbuffer_t);
impl RingBuffer {
pub fn new(size: usize) -> Result<Self, ()> {
let insize = size as libc::size_t;
let handle = unsafe { j::jack_ringbuffer_create(insize) };
if handle.is_null() {
return Err(());
}
Ok(RingBuffer(handle))
}
pub fn mlock(&mut self) {
unsafe { j::jack_ringbuffer_mlock(self.0) };
}
pub fn reset(&mut self) {
unsafe { j::jack_ringbuffer_reset(self.0) };
}
pub fn into_reader_writer(self) -> (RingBufferReader, RingBufferWriter) {
let out = unsafe { (RingBufferReader::new(self.0), RingBufferWriter::new(self.0)) };
mem::forget(self);
out
}
pub fn from_reader_writer(r: RingBufferReader, w: RingBufferWriter) -> Self {
if r.ringbuffer_handle != w.ringbuffer_handle {
panic!("mismatching read and write handles!")
}
let handle = RingBuffer(r.ringbuffer_handle);
mem::forget(r);
mem::forget(w);
handle
}
}
impl Drop for RingBuffer {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe { j::jack_ringbuffer_free(self.0) };
}
self.0 = std::ptr::null_mut();
}
}
unsafe impl Send for RingBuffer {}
unsafe impl Sync for RingBuffer {}
pub struct RingBufferReader {
ringbuffer_handle: *mut j::jack_ringbuffer_t,
both_live: AtomicBool,
}
unsafe impl Send for RingBufferReader {}
unsafe impl Sync for RingBufferReader {}
pub struct RingBufferWriter {
ringbuffer_handle: *mut j::jack_ringbuffer_t,
both_live: AtomicBool,
}
unsafe impl Send for RingBufferWriter {}
unsafe impl Sync for RingBufferWriter {}
impl RingBufferReader {
unsafe fn new(raw: *mut j::jack_ringbuffer_t) -> Self {
RingBufferReader {
ringbuffer_handle: raw,
both_live: AtomicBool::new(true),
}
}
pub fn get_vector(&self) -> (&[u8], &[u8]) {
let mut vec = [
j::jack_ringbuffer_data_t::default(),
j::jack_ringbuffer_data_t::default(),
];
let vecstart = &mut vec[0] as *mut j::jack_ringbuffer_data_t;
unsafe { j::jack_ringbuffer_get_read_vector(self.ringbuffer_handle, vecstart) };
let view1 = vec[0];
let view2 = vec[1];
let buf1 = view1.buf as *mut u8;
let len1 = view1.len as usize;
let mut buf2 = view2.buf as *mut u8;
let len2 = view2.len as usize;
if len2 == 0 {
buf2 = buf1;
}
let view1 = unsafe { std::slice::from_raw_parts(buf1, len1) };
let view2 = unsafe { std::slice::from_raw_parts(buf2, len2) };
(view1, view2)
}
pub fn read_buffer(&mut self, buf: &mut [u8]) -> usize {
if buf.is_empty() {
return 0;
}
let insize: libc::size_t = buf.len() as libc::size_t;
let bufstart = &mut buf[0] as *mut _ as *mut libc::c_char;
let read = unsafe { j::jack_ringbuffer_read(self.ringbuffer_handle, bufstart, insize) };
read as usize
}
pub fn peek(&self, buf: &mut [u8]) -> usize {
if buf.is_empty() {
return 0;
}
let insize: libc::size_t = buf.len() as libc::size_t;
let bufstart = &mut buf[0] as *mut _ as *mut libc::c_char;
let read = unsafe { j::jack_ringbuffer_peek(self.ringbuffer_handle, bufstart, insize) };
read as usize
}
pub fn advance(&mut self, cnt: usize) {
let incnt = cnt as libc::size_t;
unsafe { j::jack_ringbuffer_read_advance(self.ringbuffer_handle, incnt) };
}
pub fn space(&self) -> usize {
unsafe { j::jack_ringbuffer_read_space(self.ringbuffer_handle) as usize }
}
pub fn peek_iter<'a>(
&'a self,
) -> std::iter::Chain<std::slice::Iter<'a, u8>, std::slice::Iter<'a, u8>> {
let (view1, view2) = self.get_vector();
view1.iter().chain(view2.iter())
}
}
impl std::io::Read for RingBufferReader {
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
Ok(self.read_buffer(buf))
}
}
impl Drop for RingBufferReader {
fn drop(&mut self) {
if !self
.both_live
.compare_and_swap(true, false, Ordering::SeqCst)
{
drop(RingBuffer(self.ringbuffer_handle));
}
}
}
impl RingBufferWriter {
unsafe fn new(raw: *mut j::jack_ringbuffer_t) -> Self {
RingBufferWriter {
ringbuffer_handle: raw,
both_live: AtomicBool::new(true),
}
}
pub fn write_buffer(&mut self, buf: &[u8]) -> usize {
if buf.is_empty() {
return 0;
}
let insize: libc::size_t = buf.len() as libc::size_t;
let bufstart = &buf[0] as *const _ as *const libc::c_char;
let read = unsafe { j::jack_ringbuffer_write(self.ringbuffer_handle, bufstart, insize) };
read as usize
}
pub fn advance(&mut self, cnt: usize) {
let incnt = cnt as libc::size_t;
unsafe { j::jack_ringbuffer_write_advance(self.ringbuffer_handle, incnt) };
}
pub fn space(&mut self) -> usize {
unsafe { j::jack_ringbuffer_write_space(self.ringbuffer_handle) as usize }
}
pub fn get_vector(&mut self) -> (&mut [u8], &mut [u8]) {
let mut vec = [
j::jack_ringbuffer_data_t::default(),
j::jack_ringbuffer_data_t::default(),
];
let vecstart = &mut vec[0] as *mut j::jack_ringbuffer_data_t;
unsafe { j::jack_ringbuffer_get_write_vector(self.ringbuffer_handle, vecstart) };
let view1 = vec[0];
let view2 = vec[1];
let buf1 = view1.buf as *mut u8;
let len1 = view1.len as usize;
let mut buf2 = view2.buf as *mut u8;
let len2 = view2.len as usize;
if len2 == 0 {
buf2 = buf1;
}
let view1 = unsafe { std::slice::from_raw_parts_mut(buf1, len1) };
let view2 = unsafe { std::slice::from_raw_parts_mut(buf2, len2) };
(view1, view2)
}
pub fn peek_iter<'a>(
&'a mut self,
) -> std::iter::Chain<std::slice::IterMut<'a, u8>, std::slice::IterMut<'a, u8>> {
let (view1, view2) = self.get_vector();
view1.iter_mut().chain(view2.iter_mut())
}
}
impl std::io::Write for RingBufferWriter {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
Ok(self.write_buffer(buf))
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl Drop for RingBufferWriter {
fn drop(&mut self) {
if !self
.both_live
.compare_and_swap(true, false, Ordering::SeqCst)
{
drop(RingBuffer(self.ringbuffer_handle));
}
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn ringbuffer_can_create() {
let ringbuf = RingBuffer::new(1024);
ringbuf.unwrap();
}
#[test]
fn ringbuffer_can_space() {
const SIZE: usize = 1024;
let ringbuf = RingBuffer::new(SIZE).unwrap();
let (mut reader, mut writer) = ringbuf.into_reader_writer();
assert_eq!(writer.space(), SIZE - 1);
assert_eq!(reader.space(), 0);
const ADVANCE: usize = 5;
writer.advance(ADVANCE);
assert_eq!(writer.space(), SIZE - 1 - ADVANCE);
assert_eq!(reader.space(), ADVANCE);
reader.advance(ADVANCE);
assert_eq!(writer.space(), SIZE - 1);
assert_eq!(reader.space(), 0);
}
#[test]
fn ringbuffer_write_read() {
let ringbuf = RingBuffer::new(1024).unwrap();
let (mut reader, mut writer) = ringbuf.into_reader_writer();
let buf = [0u8, 1, 2, 3];
let num = writer.write_buffer(&buf);
assert_eq!(num, buf.len());
let mut outbuf = [0u8; 8];
let num = reader.read_buffer(&mut outbuf);
assert_eq!(num, buf.len());
assert_eq!(outbuf[..num], buf[..]);
}
#[test]
fn ringbuffer_peek_write() {
let ringbuf = RingBuffer::new(1024).unwrap();
let (reader, mut writer) = ringbuf.into_reader_writer();
let buf = [0u8, 1, 2, 3];
writer.write_buffer(&buf);
let data: Vec<u8> = reader.peek_iter().copied().collect();
assert_eq!(data.len(), buf.len());
assert_eq!(data[..], buf[..]);
}
#[test]
fn ringbuffer_write_read_split() {
const BUFSIZE: usize = 10;
let ringbuf = RingBuffer::new(BUFSIZE).unwrap();
let (mut reader, mut writer) = ringbuf.into_reader_writer();
let buf = [0u8, 1, 2, 3];
let advancedsize = BUFSIZE / (buf.len() / 2);
writer.advance(advancedsize);
reader.advance(advancedsize);
{
let (_, v2) = writer.get_vector();
assert_ne!(v2.len(), 0);
}
writer.write_buffer(&buf);
{
let (v1, _) = reader.get_vector();
assert_ne!(v1.len(), 0);
}
let data: Vec<u8> = reader.peek_iter().copied().collect();
assert_eq!(data.len(), buf.len());
assert_eq!(data[..], buf[..]);
}
#[test]
fn ringbuffer_peek_read() {
let ringbuf = RingBuffer::new(1024).unwrap();
let (mut reader, mut writer) = ringbuf.into_reader_writer();
let buf = [0u8, 1, 2, 3];
for (item, bufitem) in writer.peek_iter().zip(buf.iter()) {
*item = *bufitem;
}
writer.advance(buf.len());
let mut outbuf = [0u8; 8];
let num = reader.read_buffer(&mut outbuf);
assert_eq!(num, buf.len());
assert_eq!(outbuf[..num], buf[..]);
}
#[test]
fn ringbuffer_threaded() {
use std::thread;
let ringbuf = RingBuffer::new(1024).unwrap();
let (mut reader, mut writer) = ringbuf.into_reader_writer();
let buf = [0u8, 1, 2, 3];
thread::spawn(move || {
for (item, bufitem) in writer.peek_iter().zip(buf.iter()) {
*item = *bufitem;
}
writer.advance(buf.len());
})
.join()
.unwrap();
let mut outbuf = [0u8; 8];
let num = reader.read_buffer(&mut outbuf);
assert_eq!(num, buf.len());
assert_eq!(outbuf[..num], buf[..]);
}
}