iona 0.1.1

A high-performance, memory mirror circular buffer
Documentation
//! `IonaBuffer` is a high-performance, virtual memory-mirror implementation of a circular buffer,
//! which guarantees slices up to the capacity of the buffer are contiguous in memory. Wrapped reads
//! wrap to the same physical memory seamlessly.
//!
//! ```
//! use iona::IonaBuffer;
//!
//! let mut buffer: IonaBuffer<usize> = match IonaBuffer::with_capacity(512) {
//!     Ok(buffer) => buffer,
//!     Err(_) => panic!("Unable to allocate the buffer"),
//! };
//!
//! // No allocation/ concatenation needed!
//! buffer.fill(2);
//! assert_eq!(&buffer[buffer.capacity() - 1..buffer.capacity() + 3], &[2,2,2,2]);
//! ```
//!
//! ```text
//! VIRTUAL ADDRESS SPACE
//! ┌─────────────────────────────────┐
//! │                                 │
//! │   Page A  [0x0000 - 0x0FFF]     │──────────┐
//! │                                 │          │
//! ├─────────────────────────────────┤          ▼
//! │                                 │   ┌──────────────────┐
//! │   Page B  [0x1000 - 0x1FFF]     │──►│  PHYSICAL MEMORY │
//! │   (mirror)                      │   │                  │
//! └─────────────────────────────────┘   │  [ 0 ]  data[0]  │
//!                                       │  [ 1 ]  data[1]  │
//!                                       │  [ 2 ]  data[2]  │
//!          write ptr                    │  ...             │
//!             │                         │  [ N ]  data[N]  │◄── write ptr
//!             ▼                         │  ...             │
//!  Page A:  [ 0 |  1 |  2 | ... | N ]   │  [ 0 ]  data[0]  │◄── read ptr
//!  Page B:  [ 0 |  1 |  2 | ... | N ]   │  [ 1 ]  data[1]  │
//!             ▲                         │  ...             │
//!             │                         └──────────────────┘
//!          read ptr
//!
//!
//! KEY BENEFIT: A contiguous read/write spanning the page boundary
//! never needs to wrap — the mirror handles it transparently.
//!
//!   read ptr                     write ptr
//!      │                              │
//!      ▼                              ▼
//! Page A: [ 6 | 7 | 8 | 9 | 10 | 11 | 0 | 1 | 2 | 3 | 4 | 5 ]
//!              ╰──────────────────────────────────────╯
//!                    contiguous memcpy, no wrap logic!
//!
//! Page B: [ 6 | 7 | 8 | 9 | 10 | 11 | 0 | 1 | 2 | 3 | 4 | 5 ]
//!              ^--- same physical bytes, just offset by one page
//! ```

mod iona;

pub use iona::IonaBuffer;
pub use zerocopy;

#[cfg(feature = "derive")]
pub use iona_derive::iona;

#[cfg(feature = "derive")]
pub use zerocopy_derive;

#[cfg(test)]
mod test {
    use super::*;
    use std::iter::Sum;

    #[test]
    fn create_new_circular_buffer() {
        #[iona]
        #[derive(PartialEq, Eq, Debug, Clone, Copy)]
        struct Test {
            x: usize,
            y: usize,
        }

        impl Sum for Test {
            fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
                iter.fold(Test { x: 0, y: 0 }, |acc, test| Test {
                    x: acc.x + test.x,
                    y: acc.y + test.y,
                })
            }
        }

        impl<'a> Sum<&'a Test> for Test {
            fn sum<I: Iterator<Item = &'a Self>>(iter: I) -> Self {
                iter.fold(Test { x: 0, y: 0 }, |acc, t| Test {
                    x: acc.x + t.x,
                    y: acc.y + t.y,
                })
            }
        }

        let mut buffer: IonaBuffer<Test> = IonaBuffer::new().unwrap();

        assert_eq!(buffer.capacity(), 256);

        buffer.push_back(&Test { x: 0, y: 0 });
        buffer.push_back(&Test { x: 1, y: 0 });
        assert_eq!(buffer.get(0), Some(&Test { x: 0, y: 0 }));
        assert_eq!(buffer.get(1), Some(&Test { x: 1, y: 0 }));

        assert_eq!(
            buffer.get_slice(0..2),
            &[Test { x: 0, y: 0 }, Test { x: 1, y: 0 }]
        );
        assert_eq!(&buffer[..=1], &[Test { x: 0, y: 0 }, Test { x: 1, y: 0 }]);
        assert_eq!(&buffer[0..=1], &[Test { x: 0, y: 0 }, Test { x: 1, y: 0 }]);
        assert_eq!(
            buffer.get_slice(buffer.capacity() - 1..buffer.capacity() + 2),
            &[
                Test { x: 0, y: 0 },
                Test { x: 0, y: 0 },
                Test { x: 1, y: 0 }
            ]
        );
        assert_eq!(
            &buffer[buffer.capacity() - 1..buffer.capacity() + 2],
            &[
                Test { x: 0, y: 0 },
                Test { x: 0, y: 0 },
                Test { x: 1, y: 0 }
            ]
        );
    }

    #[test]
    fn buff_to_iter() {
        let mut buffer: IonaBuffer<usize> = IonaBuffer::new().unwrap();

        buffer.push_back(&1);

        assert_eq!(buffer[..].iter().last().unwrap(), &1);
        assert_eq!(buffer.iter().last().unwrap(), &1);
        assert_eq!(buffer.iter_mut().last().unwrap(), &mut 1);

        buffer.push_back(&1);
    }
}