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 {
29            request_tx,
30        }
31    }
32
33    // Public API for requesting an image - this hides the channel communication
34    pub fn get_image(&self, path: PathBuf) -> CacheResult<Arc<DynamicImage>> {
35        // Create a one-shot channel for the response
36        let (response_tx, response_rx) = oneshot::channel();
37
38        // Send the request through the unbounded channel
39        self.request_tx
40            .send(CacheRequest::GetImage {
41                path,
42                response_tx,
43            })
44            .map_err(|_| {
45                crate::CacheError::Config(
46                    "Cache manager is shutdown".to_string(),
47                )
48            })?;
49
50        // Wait for and return the response
51        response_rx.blocking_recv().map_err(|_| {
52            crate::CacheError::Config(
53                "Cache manager stopped responding".to_string(),
54            )
55        })?
56    }
57
58    pub fn cache_image(&self, path: PathBuf) -> CacheResult<()> {
59        let (response_tx, _response_rx) = oneshot::channel();
60
61        self.request_tx
62            .send(CacheRequest::CacheImage {
63                path,
64                response_tx,
65            })
66            .map_err(|_| {
67                crate::CacheError::Config(
68                    "Cache manager is shutdown".to_string(),
69                )
70            })?;
71
72        Ok(())
73    }
74}
75
76use image::DynamicImage;
77
78#[derive(Clone)]
79pub struct CacheConfig {
80    pub max_image_count: usize,
81    pub thread_count:    usize,
82}
83
84impl Default for CacheConfig {
85    fn default() -> Self {
86        Self {
87            max_image_count: 100, thread_count: 4
88        }
89    }
90}
91
92pub(crate) struct CacheState {
93    pub entries:  HashMap<PathBuf, DynamicImage>,
94    pub lru_list: Vec<PathBuf>,
95}
96
97impl CacheState {
98    pub fn new() -> Self {
99        debug!("Initializing new cache state");
100
101        Self {
102            entries: HashMap::new(), lru_list: Vec::new()
103        }
104    }
105}
106
107impl CacheConfig {
108    const MAX_IMAGE_COUNT: usize = 1000;
109    const MAX_THREAD_COUNT: usize = 32;
110    const MIN_IMAGE_COUNT: usize = 10;
111    const MIN_THREAD_COUNT: usize = 1;
112
113    pub fn validate(&self) -> CacheResult<()> {
114        if self.thread_count < Self::MIN_THREAD_COUNT
115            || self.thread_count > Self::MAX_THREAD_COUNT
116        {
117            return Err(CacheError::Config(format!(
118                "Thread count must be between {} and {}",
119                Self::MIN_THREAD_COUNT,
120                Self::MAX_THREAD_COUNT
121            )));
122        }
123
124        if self.max_image_count < Self::MIN_IMAGE_COUNT
125            || self.max_image_count > Self::MAX_IMAGE_COUNT
126        {
127            return Err(CacheError::Config(format!(
128                "Max image count must be between {} and {}",
129                Self::MIN_IMAGE_COUNT,
130                Self::MAX_IMAGE_COUNT
131            )));
132        }
133
134        Ok(())
135    }
136}