ruvector_cognitive_container/
memory.rs1use serde::{Deserialize, Serialize};
2
3use crate::error::{ContainerError, Result};
4
5#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct MemoryConfig {
11 pub slab_size: usize,
13 pub graph_budget: usize,
15 pub feature_budget: usize,
17 pub solver_budget: usize,
19 pub witness_budget: usize,
21 pub evidence_budget: usize,
23}
24
25impl Default for MemoryConfig {
26 fn default() -> Self {
27 Self {
28 slab_size: 4 * 1024 * 1024, graph_budget: 1024 * 1024, feature_budget: 1024 * 1024, solver_budget: 512 * 1024, witness_budget: 512 * 1024, evidence_budget: 1024 * 1024, }
35 }
36}
37
38impl MemoryConfig {
39 pub fn validate(&self) -> Result<()> {
41 let sum = self.graph_budget
42 + self.feature_budget
43 + self.solver_budget
44 + self.witness_budget
45 + self.evidence_budget;
46 if sum != self.slab_size {
47 return Err(ContainerError::InvalidConfig {
48 reason: format!(
49 "budget sum ({sum}) does not equal slab_size ({})",
50 self.slab_size
51 ),
52 });
53 }
54 Ok(())
55 }
56}
57
58pub struct MemorySlab {
60 data: Vec<u8>,
61 config: MemoryConfig,
62}
63
64impl MemorySlab {
65 pub fn new(config: MemoryConfig) -> Result<Self> {
67 config.validate()?;
68 Ok(Self {
69 data: vec![0u8; config.slab_size],
70 config,
71 })
72 }
73
74 pub fn total_size(&self) -> usize {
76 self.data.len()
77 }
78
79 pub fn as_bytes(&self) -> &[u8] {
81 &self.data
82 }
83
84 pub fn config(&self) -> &MemoryConfig {
86 &self.config
87 }
88}
89
90pub struct Arena {
95 base_offset: usize,
96 size: usize,
97 offset: usize,
98}
99
100impl Arena {
101 pub fn new(base_offset: usize, size: usize) -> Self {
103 Self {
104 base_offset,
105 size,
106 offset: 0,
107 }
108 }
109
110 pub fn alloc(&mut self, size: usize, align: usize) -> Result<usize> {
114 let align = align.max(1);
115 let current = self.base_offset + self.offset;
116 let aligned = (current + align - 1) & !(align - 1);
117 let padding = aligned - current;
118 let total = padding + size;
119
120 if self.offset + total > self.size {
121 return Err(ContainerError::AllocationFailed {
122 requested: size,
123 available: self.remaining(),
124 });
125 }
126
127 self.offset += total;
128 Ok(aligned)
129 }
130
131 pub fn reset(&mut self) {
133 self.offset = 0;
134 }
135
136 pub fn used(&self) -> usize {
138 self.offset
139 }
140
141 pub fn remaining(&self) -> usize {
143 self.size.saturating_sub(self.offset)
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
152 fn test_memory_slab_creation() {
153 let config = MemoryConfig::default();
154 let slab = MemorySlab::new(config).expect("slab should allocate");
155 assert_eq!(slab.total_size(), 4 * 1024 * 1024);
156 assert_eq!(slab.as_bytes().len(), slab.total_size());
157 assert!(slab.as_bytes().iter().all(|&b| b == 0));
159 }
160
161 #[test]
162 fn test_memory_config_validation_fails_on_mismatch() {
163 let config = MemoryConfig {
164 slab_size: 100,
165 graph_budget: 10,
166 feature_budget: 10,
167 solver_budget: 10,
168 witness_budget: 10,
169 evidence_budget: 10,
170 };
171 assert!(MemorySlab::new(config).is_err());
172 }
173
174 #[test]
175 fn test_arena_allocation() {
176 let mut arena = Arena::new(0, 256);
177 assert_eq!(arena.remaining(), 256);
178 assert_eq!(arena.used(), 0);
179
180 let off1 = arena.alloc(64, 8).expect("alloc 64");
181 assert_eq!(off1, 0); assert_eq!(arena.used(), 64);
183 assert_eq!(arena.remaining(), 192);
184
185 let off2 = arena.alloc(32, 16).expect("alloc 32");
186 assert_eq!(off2, 64);
188 assert_eq!(arena.used(), 96);
189
190 arena.reset();
191 assert_eq!(arena.used(), 0);
192 assert_eq!(arena.remaining(), 256);
193 }
194
195 #[test]
196 fn test_arena_allocation_overflow() {
197 let mut arena = Arena::new(0, 64);
198 assert!(arena.alloc(128, 1).is_err());
199 }
200
201 #[test]
202 fn test_arena_alignment_padding() {
203 let mut arena = Arena::new(0, 256);
204 let _ = arena.alloc(1, 1).unwrap();
206 assert_eq!(arena.used(), 1);
207 let off = arena.alloc(8, 16).unwrap();
209 assert_eq!(off, 16);
210 assert_eq!(arena.used(), 24);
212 }
213}