Skip to main content

synaptic_cache/
in_memory.rs

1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4use async_trait::async_trait;
5use synaptic_core::{ChatResponse, SynapseError};
6use tokio::sync::RwLock;
7
8use crate::LlmCache;
9
10struct CacheEntry {
11    response: ChatResponse,
12    created_at: Instant,
13}
14
15/// In-memory LLM response cache with optional TTL expiration.
16pub struct InMemoryCache {
17    store: RwLock<HashMap<String, CacheEntry>>,
18    ttl: Option<Duration>,
19}
20
21impl InMemoryCache {
22    /// Create a new cache with no TTL (entries never expire).
23    pub fn new() -> Self {
24        Self {
25            store: RwLock::new(HashMap::new()),
26            ttl: None,
27        }
28    }
29
30    /// Create a new cache where entries expire after the given duration.
31    pub fn with_ttl(duration: Duration) -> Self {
32        Self {
33            store: RwLock::new(HashMap::new()),
34            ttl: Some(duration),
35        }
36    }
37}
38
39impl Default for InMemoryCache {
40    fn default() -> Self {
41        Self::new()
42    }
43}
44
45#[async_trait]
46impl LlmCache for InMemoryCache {
47    async fn get(&self, key: &str) -> Result<Option<ChatResponse>, SynapseError> {
48        let store = self.store.read().await;
49        match store.get(key) {
50            Some(entry) => {
51                if let Some(ttl) = self.ttl {
52                    if entry.created_at.elapsed() > ttl {
53                        return Ok(None);
54                    }
55                }
56                Ok(Some(entry.response.clone()))
57            }
58            None => Ok(None),
59        }
60    }
61
62    async fn put(&self, key: &str, response: &ChatResponse) -> Result<(), SynapseError> {
63        let mut store = self.store.write().await;
64        store.insert(
65            key.to_string(),
66            CacheEntry {
67                response: response.clone(),
68                created_at: Instant::now(),
69            },
70        );
71        Ok(())
72    }
73
74    async fn clear(&self) -> Result<(), SynapseError> {
75        let mut store = self.store.write().await;
76        store.clear();
77        Ok(())
78    }
79}