1pub mod detect;
2#[cfg(target_os = "linux")]
3pub mod portal;
4pub mod xcap_backend;
5
6use chrono::{DateTime, Utc};
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10use uuid::Uuid;
11
12#[derive(Debug, Clone, Serialize, Deserialize)]
13pub enum CaptureMode {
14 Fullscreen,
15 Monitor(u32),
16 Region { x: i32, y: i32, w: u32, h: u32 },
17 Window(u64),
18}
19
20#[derive(Debug, Clone, Serialize, Deserialize)]
21pub struct CaptureMetadata {
22 pub timestamp: DateTime<Utc>,
23 pub mode: CaptureMode,
24 pub monitor: Option<String>,
25 pub window_title: Option<String>,
26 pub dimensions: (u32, u32),
27}
28
29#[derive(Debug)]
30pub struct CaptureResult {
31 pub id: Uuid,
32 pub image: Arc<image::DynamicImage>,
33 pub metadata: CaptureMetadata,
34}
35
36#[derive(Clone)]
39pub struct ImageStore {
40 images: Arc<RwLock<HashMap<Uuid, Arc<image::DynamicImage>>>>,
41}
42
43impl ImageStore {
44 pub fn new() -> Self {
45 Self {
46 images: Arc::new(RwLock::new(HashMap::new())),
47 }
48 }
49
50 pub fn insert(&self, id: Uuid, image: Arc<image::DynamicImage>) {
51 self.images
52 .write()
53 .unwrap_or_else(|e| e.into_inner())
54 .insert(id, image);
55 }
56
57 pub fn get(&self, id: &Uuid) -> Option<Arc<image::DynamicImage>> {
58 self.images
59 .read()
60 .unwrap_or_else(|e| e.into_inner())
61 .get(id)
62 .cloned()
63 }
64
65 pub fn ids(&self) -> Vec<Uuid> {
66 self.images
67 .read()
68 .unwrap_or_else(|e| e.into_inner())
69 .keys()
70 .copied()
71 .collect()
72 }
73
74 pub fn remove(&self, id: &Uuid) -> Option<Arc<image::DynamicImage>> {
75 self.images
76 .write()
77 .unwrap_or_else(|e| e.into_inner())
78 .remove(id)
79 }
80}
81
82impl Default for ImageStore {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use image::{DynamicImage, RgbaImage};
92
93 fn dummy_image() -> Arc<DynamicImage> {
94 Arc::new(DynamicImage::ImageRgba8(RgbaImage::new(10, 10)))
95 }
96
97 #[test]
98 fn image_store_insert_and_get() {
99 let store = ImageStore::new();
100 let id = Uuid::new_v4();
101 let img = dummy_image();
102 store.insert(id, img.clone());
103 assert!(store.get(&id).is_some());
104 }
105
106 #[test]
107 fn image_store_get_missing_returns_none() {
108 let store = ImageStore::new();
109 assert!(store.get(&Uuid::new_v4()).is_none());
110 }
111
112 #[test]
113 fn image_store_remove_clears_entry() {
114 let store = ImageStore::new();
115 let id = Uuid::new_v4();
116 store.insert(id, dummy_image());
117 assert!(store.remove(&id).is_some());
118 assert!(store.get(&id).is_none());
119 }
120
121 #[test]
122 fn image_store_get_after_remove_is_none() {
123 let store = ImageStore::new();
124 let id = Uuid::new_v4();
125 store.insert(id, dummy_image());
126 store.remove(&id);
127 assert!(store.get(&id).is_none());
128 }
129}