#![allow(missing_docs)]
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use super::{MemoryType, ProtectionLevel};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootIndex {
pub version: u64,
pub updated_at: DateTime<Utc>,
pub active_context: Vec<RootEntry>,
pub recent_patterns: Vec<String>,
pub historical_summary: Vec<HistoricalPeriod>,
pub topics: Vec<TopicEntry>,
}
impl Default for RootIndex {
fn default() -> Self {
Self {
version: 0,
updated_at: Utc::now(),
active_context: Vec::new(),
recent_patterns: Vec::new(),
historical_summary: Vec::new(),
topics: Vec::new(),
}
}
}
impl RootIndex {
pub fn new() -> Self {
Self::default()
}
pub fn estimated_tokens(&self) -> usize {
let total_chars: usize = self
.active_context
.iter()
.map(|e| e.topic.len() + e.reference.len())
.chain(self.recent_patterns.iter().map(|p| p.len()))
.chain(
self.topics
.iter()
.map(|t| t.name.len() + t.description.len()),
)
.sum();
total_chars / 4
}
pub fn topic_matches_query(&self, topic: &TopicEntry, query: &str) -> bool {
let query_lower = query.to_lowercase();
topic.name.to_lowercase().contains(&query_lower)
|| topic.description.to_lowercase().contains(&query_lower)
|| topic.category.to_lowercase().contains(&query_lower)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RootEntry {
pub topic: String,
pub memory_type: MemoryType,
pub protection: ProtectionLevel,
pub age_days: u32,
pub reference: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HistoricalPeriod {
pub period: String,
pub summary: String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TopicEntry {
pub name: String,
pub category: String,
pub age_days: u32,
pub description: String,
pub reference: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_root_index_default() {
let idx = RootIndex::default();
assert_eq!(idx.version, 0);
assert!(idx.active_context.is_empty());
assert!(idx.topics.is_empty());
}
#[test]
fn test_estimated_tokens() {
let mut idx = RootIndex::new();
idx.topics.push(TopicEntry {
name: "Rust async runtime".to_string(),
category: "project".to_string(),
age_days: 5,
description: "Using Tokio for async".to_string(),
reference: "fact-123".to_string(),
});
let tokens = idx.estimated_tokens();
assert!(tokens > 0, "Should have some estimated tokens");
}
#[test]
fn test_topic_matches_query() {
let idx = RootIndex::new();
let topic = TopicEntry {
name: "Memory consolidation".to_string(),
category: "architecture".to_string(),
age_days: 3,
description: "RFC-008 tiered memory system".to_string(),
reference: "dec-456".to_string(),
};
assert!(idx.topic_matches_query(&topic, "memory"));
assert!(idx.topic_matches_query(&topic, "consolidation"));
assert!(idx.topic_matches_query(&topic, "architecture"));
assert!(!idx.topic_matches_query(&topic, "deployment"));
}
}