ferrite_cache/
types.rs

1use std::{collections::HashMap, path::PathBuf, sync::Arc};
2use tracing::debug;
3
4use crate::{CacheError, CacheResult};
5use tokio::sync::oneshot;
6
7#[derive(Debug)]
8pub enum CacheRequest {
9    CacheImage {
10        path: PathBuf,
11        response_tx: oneshot::Sender<CacheResult<()>>, // Changed return type
12    },
13    GetImage {
14        path: PathBuf,
15        response_tx: oneshot::Sender<CacheResult<Arc<DynamicImage>>>,
16    },
17}
18
19// Structure to handle communication with the cache manager
20pub struct CacheHandle {
21    request_tx: tokio::sync::mpsc::UnboundedSender<CacheRequest>,
22}
23
24impl CacheHandle {
25    pub fn new(
26        request_tx: tokio::sync::mpsc::UnboundedSender<CacheRequest>,
27    ) -> Self {
28        Self { request_tx }
29    }
30
31    // Public API for requesting an image - this hides the channel communication
32    pub fn get_image(&self, path: PathBuf) -> CacheResult<Arc<DynamicImage>> {
33        // Create a one-shot channel for the response
34        let (response_tx, response_rx) = oneshot::channel();
35
36        // Send the request through the unbounded channel
37        self.request_tx
38            .send(CacheRequest::GetImage { path, response_tx })
39            .map_err(|_| {
40                crate::CacheError::Config(
41                    "Cache manager is shutdown".to_string(),
42                )
43            })?;
44
45        // Wait for and return the response
46        response_rx.blocking_recv().map_err(|_| {
47            crate::CacheError::Config(
48                "Cache manager stopped responding".to_string(),
49            )
50        })?
51    }
52
53    pub fn cache_image(&self, path: PathBuf) -> CacheResult<()> {
54        let (response_tx, _response_rx) = oneshot::channel();
55
56        self.request_tx
57            .send(CacheRequest::CacheImage { path, response_tx })
58            .map_err(|_| {
59                crate::CacheError::Config(
60                    "Cache manager is shutdown".to_string(),
61                )
62            })?;
63
64        Ok(())
65    }
66}
67
68use image::DynamicImage;
69
70#[derive(Clone, Debug)]
71pub struct CacheConfig {
72    pub max_image_count: usize,
73    pub thread_count: usize,
74}
75
76impl Default for CacheConfig {
77    fn default() -> Self {
78        Self { max_image_count: 100, thread_count: 4 }
79    }
80}
81
82pub(crate) struct CacheState {
83    pub entries: HashMap<PathBuf, DynamicImage>,
84    pub lru_list: Vec<PathBuf>,
85}
86
87impl CacheState {
88    pub fn new() -> Self {
89        debug!("Initializing new cache state");
90
91        Self { entries: HashMap::new(), lru_list: Vec::new() }
92    }
93}
94
95impl CacheConfig {
96    const MAX_IMAGE_COUNT: usize = 1000;
97    const MAX_THREAD_COUNT: usize = 32;
98    const MIN_IMAGE_COUNT: usize = 10;
99    const MIN_THREAD_COUNT: usize = 1;
100
101    pub fn validate(&self) -> CacheResult<()> {
102        if self.thread_count < Self::MIN_THREAD_COUNT
103            || self.thread_count > Self::MAX_THREAD_COUNT
104        {
105            return Err(CacheError::Config(format!(
106                "Thread count must be between {} and {}",
107                Self::MIN_THREAD_COUNT,
108                Self::MAX_THREAD_COUNT
109            )));
110        }
111
112        if self.max_image_count < Self::MIN_IMAGE_COUNT
113            || self.max_image_count > Self::MAX_IMAGE_COUNT
114        {
115            return Err(CacheError::Config(format!(
116                "Max image count must be between {} and {}",
117                Self::MIN_IMAGE_COUNT,
118                Self::MAX_IMAGE_COUNT
119            )));
120        }
121
122        Ok(())
123    }
124}