# iona
ion*a* → *a*ion wrapped:
> Aion (from Hellenistic Greek: αἰών, romanized: aión, lit. 'long period of time', [ai̯ˈɔːn]) is a Hellenistic deity associated with time, the orb or circle encompassing the universe, and the zodiac. The "time" which Aion represents is perpetual, unbounded, ritual, and cyclic: The future is a returning version of the past, later called aevum
> -- [wikipedia](<https://en.wikipedia.org/wiki/Aion_(deity)>)
---
`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"),
};
buffer.fill(0);
buffer.push_back(513); // this is now at the physical address 1
// No allocation/ concatenation needed when reading from the end of the physical buffer (the
// value `511`) to the next two values that were pushed to the back!
assert_eq!(buffer.get_from(509).to(3), Some([511,512,513].as_slice()));
```
```text
VIRTUAL ADDRESS SPACE
┌─────────────────────────────────┐
│ │
│ Page A [0x0000 - 0x0FFF] │──────────┐
│ │ │
├─────────────────────────────────┤ ▼
│ │ ┌──────────────────┐
│ Page B [0x1000 - 0x1FFF] │──►│ PHYSICAL MEMORY │
│ (mirror) │ │ │
└─────────────────────────────────┘ │ [ 0 ] data[0] │
│ [ 1 ] data[1] │
│ [ 2 ] data[2] │
│ ... │
│ [ N ] data[N] │
└──────────────────┘
KEY BENEFIT: A contiguous read/write spanning the page boundary
never needs to wrap — the mirror handles it transparently.
The following
Page A Page B
| │ │ | B addresses, but slices span from Page A to
| ▼ ▼ | Page B.
[ 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 0 | 1 | 2 | .. ]
╰─────────────────────────────────────╯
contiguous slice, no wrap logic!
```
# Trade-Offs
- **Increased memory use**: we double the used virtual memory space, but still only have a
single instance of physical memory backing the buffer. Moreover, this implementation
requires that the buffer is mapped to page size, which is typically 4KiB. So if
`size_of::<T>()` is small, the buffer will be relatively large and inefficient with memory
use. The buffer also grows in size by powers of 2, so if 4KiB isn't large enough, the next
buffer size, on most machines, will be 8KiB.
# Indexing
`IonaBuffer` implements the [Index](https://doc.rust-lang.org/std/ops/trait.Index.html) trait,
allowing you to access value by indexes:
```
# use iona::IonaBuffer;
#
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = IonaBuffer::try_from([0,2,4,6])?;
assert_eq!(buffer[1], 2);
# Ok(())
# }
```
However, indexing into a location outside of the `IonaBuffer` will panic! i.e.:
```should_panic
# use iona::IonaBuffer;
#
# fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut buffer = IonaBuffer::try_from([0,2,4,6])?;
println!("{}", buffer[5]); // This will panic!
# Ok(())
# }
```