atomic_pingpong 0.2.3

Lightweight no_std ping-pong buffer, using AtomicU8 for synchronization
Documentation
use atomic_pingpong::Buffer;

#[test]
fn swap_after_read() {
    let b: Buffer<i32> = Buffer::default();
    *b.write().unwrap() = 1;
    let r = b.read().unwrap();
    *b.write().unwrap() = 2;
    assert_eq!(*r, 1);
    drop(r);
    assert_eq!(*b.read().unwrap(), 2);
    assert_eq!(*b.read().unwrap(), 2);
}

#[test]
fn swap_after_write() {
    let b: Buffer<i32> = Buffer::default();
    *b.write().unwrap() = 1;
    let mut w = b.write().unwrap();
    *w = 2;
    assert_eq!(*b.read().unwrap(), 1);
    drop(w);
    assert_eq!(*b.read().unwrap(), 2);
    assert_eq!(*b.read().unwrap(), 2);
}

#[test]
fn no_swap_after_interleaved() {
    let b: Buffer<i32> = Buffer::default();
    let mut w = b.write().unwrap();
    *w = 1;
    let r = b.read().unwrap();
    drop(w);
    assert_eq!(*r, 0);
    drop(r);
    assert_eq!(*b.read().unwrap(), 1);
    assert_eq!(*b.read().unwrap(), 1);
}

#[test]
fn no_double_read() {
    let b: Buffer<i32> = Buffer::default();
    let r = b.read().unwrap();
    assert!(b.read().is_none());
    drop(r);
    assert_eq!(*b.read().unwrap(), 0);
}

#[test]
fn no_double_write() {
    let b: Buffer<i32> = Buffer::default();
    let w = b.write().unwrap();
    assert!(b.write().is_none());
    drop(w);
    assert!(b.write().is_some());
}

#[test]
fn read_once() {
    let b: Buffer<i32> = Buffer::default();
    assert!(b.read_once().is_none());
    *b.write().unwrap() = 1;
    assert_eq!(*b.read_once().unwrap(), 1);
    assert!(b.read_once().is_none());
}

#[test]
fn read_once_after_read() {
    let b: Buffer<i32> = Buffer::default();
    let r = b.read().unwrap();
    *b.write().unwrap() = 1;
    assert!(b.read_once().is_none());
    drop(r);
    assert_eq!(*b.read_once().unwrap(), 1);
}

#[test]
fn write_no_discard() {
    let b: Buffer<i32> = Buffer::default();
    *b.write_no_discard().unwrap() = 1;
    assert!(b.write_no_discard().is_none());
    assert!(b.read().is_some());
    assert!(b.write_no_discard().is_some());
}

#[test]
fn write_no_discard_while_reading() {
    let b: Buffer<i32> = Buffer::default();
    let r = b.read().unwrap();
    *b.write_no_discard().unwrap() = 1;
    assert!(b.write_no_discard().is_none());
    drop(r);
    assert!(b.write_no_discard().is_none());
    assert_eq!(*b.read_once().unwrap(), 1);
    assert!(b.write_no_discard().is_some());
}

#[test]
fn release_read() {
    let b: Buffer<i32> = Buffer::default();
    let r = b.read().unwrap();
    core::mem::forget(r);
    assert!(b.read().is_none());
    unsafe { b.release_read() };
    assert!(b.read().is_some());
}

#[test]
fn release_write() {
    let b: Buffer<i32> = Buffer::default();
    let w = b.write().unwrap();
    core::mem::forget(w);
    assert!(b.write().is_none());
    unsafe { b.release_write() };
    assert!(b.write().is_some());
}

#[test]
fn read_unchecked() {
    let b: Buffer<i32> = Buffer::default();
    assert_eq!(unsafe { *b.read_unchecked() }, 0);
    *b.write().unwrap() = 1;
    assert_eq!(unsafe { *b.read_unchecked() }, 1);
    *b.write().unwrap() = 2;
    unsafe { b.release_read() };
    assert_eq!(*b.read().unwrap(), 2);
}

#[test]
fn write_unchecked_and_read_once() {
    let b: Buffer<i32> = Buffer::default();
    assert!(b.read_once().is_none());
    unsafe { *b.write_unchecked() = 1 };
    assert!(b.read_once().is_none());
    unsafe { *b.write_unchecked() = 2 };
    assert_eq!(*b.read_once().unwrap(), 1);
    unsafe { b.release_write() };
    assert_eq!(*b.read_once().unwrap(), 2);
}