use serde::{Deserialize, Serialize};
use super::LineageId;
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[repr(C)]
pub struct Engram {
pub timestamp: u64,
pub stimulation: f32,
pub payload_id: u32,
pub source_id: u32,
pub prev_index: u32,
}
impl Default for Engram {
fn default() -> Self {
Self {
timestamp: 0,
stimulation: 0.0,
payload_id: u32::MAX,
source_id: u32::MAX,
prev_index: u32::MAX,
}
}
}
impl Engram {
pub fn new(timestamp: u64, stimulation: f32) -> Self {
Self {
timestamp,
stimulation,
..Default::default()
}
}
pub fn with_payload(timestamp: u64, stimulation: f32, payload_id: u32) -> Self {
Self {
timestamp,
stimulation,
payload_id,
..Default::default()
}
}
#[inline]
pub fn has_payload(&self) -> bool {
self.payload_id != u32::MAX
}
#[inline]
pub fn is_oldest(&self) -> bool {
self.prev_index == u32::MAX
}
}
pub struct StrataArena {
data: Vec<Engram>,
depth: usize,
_capacity: usize,
}
impl StrataArena {
pub fn with_capacity(max_lineages: usize, depth: usize) -> Self {
let total_size = max_lineages * depth;
Self {
data: vec![Engram::default(); total_size],
depth,
_capacity: max_lineages,
}
}
#[inline]
pub fn depth(&self) -> usize {
self.depth
}
#[inline]
fn base_index(&self, lineage: LineageId) -> usize {
lineage.index() * self.depth
}
pub fn record(&mut self, lineage: LineageId, current_head: u32, engram: Engram) -> u32 {
let base = self.base_index(lineage);
let slot_offset = if current_head == u32::MAX {
0
} else {
let current_offset = (current_head as usize) - base;
(current_offset + 1) % self.depth
};
let global_index = base + slot_offset;
let mut new_engram = engram;
if current_head != u32::MAX {
new_engram.prev_index = current_head;
}
self.data[global_index] = new_engram;
global_index as u32
}
#[inline]
pub fn get(&self, index: u32) -> Option<&Engram> {
self.data.get(index as usize)
}
pub fn history(&self, head_index: u32) -> impl Iterator<Item = &Engram> {
HistoryIter {
arena: self,
current: head_index,
remaining: self.depth,
}
}
pub fn as_slice(&self) -> &[Engram] {
&self.data
}
}
struct HistoryIter<'a> {
arena: &'a StrataArena,
current: u32,
remaining: usize,
}
impl<'a> Iterator for HistoryIter<'a> {
type Item = &'a Engram;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 || self.current == u32::MAX {
return None;
}
let engram = self.arena.get(self.current)?;
self.current = engram.prev_index;
self.remaining -= 1;
Some(engram)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_engram_default() {
let e = Engram::default();
assert!(!e.has_payload());
assert!(e.is_oldest());
}
#[test]
fn test_strata_arena_record() {
let mut arena = StrataArena::with_capacity(10, 4);
let lineage = LineageId(0);
let head1 = arena.record(lineage, u32::MAX, Engram::new(1000, 0.5));
assert_eq!(head1, 0);
let head2 = arena.record(lineage, head1, Engram::new(2000, 0.7));
assert_eq!(head2, 1);
let e2 = arena.get(head2).unwrap();
assert_eq!(e2.prev_index, head1);
}
#[test]
fn test_history_iteration() {
let mut arena = StrataArena::with_capacity(10, 4);
let lineage = LineageId(0);
let head1 = arena.record(lineage, u32::MAX, Engram::new(1000, 0.1));
let head2 = arena.record(lineage, head1, Engram::new(2000, 0.2));
let head3 = arena.record(lineage, head2, Engram::new(3000, 0.3));
let history: Vec<_> = arena.history(head3).collect();
assert_eq!(history.len(), 3);
assert_eq!(history[0].stimulation, 0.3); assert_eq!(history[1].stimulation, 0.2);
assert_eq!(history[2].stimulation, 0.1);
}
#[test]
fn test_ring_buffer_wrap() {
let mut arena = StrataArena::with_capacity(10, 3); let lineage = LineageId(0);
let h1 = arena.record(lineage, u32::MAX, Engram::new(1000, 0.1));
let h2 = arena.record(lineage, h1, Engram::new(2000, 0.2));
let h3 = arena.record(lineage, h2, Engram::new(3000, 0.3));
let h4 = arena.record(lineage, h3, Engram::new(4000, 0.4));
assert_eq!(h4, 0);
assert_eq!(arena.get(h4).unwrap().prev_index, h3);
}
}