1use std::time::SystemTime;
4
5use crate::error::ProfileError;
6use crate::models::Keybind;
7use std::collections::HashMap;
8
9#[derive(Debug, Clone)]
11pub struct Profile {
12 pub name: String,
13 pub keybinds: Vec<Keybind>,
14 pub created_at: SystemTime,
15 pub modified_at: SystemTime,
16}
17
18impl serde::Serialize for Profile {
20 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21 where
22 S: serde::Serializer,
23 {
24 use serde::ser::SerializeStruct;
25 let mut state = serializer.serialize_struct("Profile", 2)?;
26 state.serialize_field("name", &self.name)?;
27 state.serialize_field("keybinds", &self.keybinds)?;
28 state.end()
29 }
30}
31
32impl<'de> serde::Deserialize<'de> for Profile {
34 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
35 where
36 D: serde::Deserializer<'de>,
37 {
38 use serde::de::{self, MapAccess, Visitor};
39 use std::fmt;
40
41 #[derive(serde::Deserialize)]
42 #[serde(field_identifier, rename_all = "lowercase")]
43 enum Field {
44 Name,
45 Keybinds,
46 }
47
48 struct ProfileVisitor;
49
50 impl<'de> Visitor<'de> for ProfileVisitor {
51 type Value = Profile;
52
53 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
54 formatter.write_str("struct Profile")
55 }
56
57 fn visit_map<V>(self, mut map: V) -> Result<Profile, V::Error>
58 where
59 V: MapAccess<'de>,
60 {
61 let mut name = None;
62 let mut keybinds = None;
63
64 while let Some(key) = map.next_key()? {
65 match key {
66 Field::Name => {
67 if name.is_some() {
68 return Err(de::Error::duplicate_field("name"));
69 }
70 name = Some(map.next_value()?);
71 }
72 Field::Keybinds => {
73 if keybinds.is_some() {
74 return Err(de::Error::duplicate_field("keybinds"));
75 }
76 keybinds = Some(map.next_value()?);
77 }
78 }
79 }
80
81 let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
82 let keybinds = keybinds.ok_or_else(|| de::Error::missing_field("keybinds"))?;
83 let now = SystemTime::now();
84
85 Ok(Profile {
86 name,
87 keybinds,
88 created_at: now,
89 modified_at: now,
90 })
91 }
92 }
93
94 deserializer.deserialize_struct("Profile", &["name", "keybinds"], ProfileVisitor)
95 }
96}
97
98impl Profile {
99 pub fn new(name: impl Into<String>, keybinds: Vec<Keybind>) -> Self {
101 let now = SystemTime::now();
102 Profile {
103 name: name.into(),
104 keybinds,
105 created_at: now,
106 modified_at: now,
107 }
108 }
109}
110
111pub struct ProfileManager {
113 profiles: HashMap<String, Profile>,
114 active_profile: Option<String>,
115}
116
117impl ProfileManager {
118 pub fn new() -> Self {
120 ProfileManager {
121 profiles: HashMap::new(),
122 active_profile: None,
123 }
124 }
125
126 pub fn create_profile(
128 &mut self,
129 name: impl Into<String>,
130 keybinds: Vec<Keybind>,
131 ) -> Result<(), ProfileError> {
132 let name = name.into();
133
134 if name.is_empty() {
135 return Err(ProfileError::InvalidProfileName(
136 "Profile name cannot be empty".to_string(),
137 ));
138 }
139
140 if self.profiles.contains_key(&name) {
141 return Err(ProfileError::ProfileAlreadyExists(name));
142 }
143
144 let profile = Profile::new(name.clone(), keybinds);
145 self.profiles.insert(name, profile);
146
147 if self.active_profile.is_none() {
149 self.active_profile = Some(self.profiles.keys().next().unwrap().clone());
150 }
151
152 Ok(())
153 }
154
155 pub fn select_profile(&mut self, name: &str) -> Result<(), ProfileError> {
157 if !self.profiles.contains_key(name) {
158 return Err(ProfileError::ProfileNotFound(name.to_string()));
159 }
160
161 self.active_profile = Some(name.to_string());
162 Ok(())
163 }
164
165 pub fn delete_profile(&mut self, name: &str) -> Result<(), ProfileError> {
167 if let Some(active) = &self.active_profile {
168 if active == name {
169 return Err(ProfileError::CannotDeleteActiveProfile(name.to_string()));
170 }
171 }
172
173 if self.profiles.remove(name).is_none() {
174 return Err(ProfileError::ProfileNotFound(name.to_string()));
175 }
176
177 Ok(())
178 }
179
180 pub fn list_profiles(&self) -> Vec<&Profile> {
182 self.profiles.values().collect()
183 }
184
185 pub fn get_active_profile(&self) -> Result<&Profile, ProfileError> {
187 let name = self
188 .active_profile
189 .as_ref()
190 .ok_or(ProfileError::NoActiveProfile)?;
191
192 self.profiles
193 .get(name)
194 .ok_or_else(|| ProfileError::ProfileNotFound(name.clone()))
195 }
196
197 pub fn get_profile(&self, name: &str) -> Option<&Profile> {
199 self.profiles.get(name)
200 }
201
202 pub fn active_profile_name(&self) -> Option<&str> {
204 self.active_profile.as_deref()
205 }
206
207 pub fn update_profile(
209 &mut self,
210 name: &str,
211 keybinds: Vec<Keybind>,
212 ) -> Result<(), ProfileError> {
213 let profile = self
214 .profiles
215 .get_mut(name)
216 .ok_or_else(|| ProfileError::ProfileNotFound(name.to_string()))?;
217
218 profile.keybinds = keybinds;
219 profile.modified_at = SystemTime::now();
220
221 Ok(())
222 }
223
224 pub fn len(&self) -> usize {
226 self.profiles.len()
227 }
228
229 pub fn is_empty(&self) -> bool {
231 self.profiles.is_empty()
232 }
233}
234
235impl Default for ProfileManager {
236 fn default() -> Self {
237 Self::new()
238 }
239}
240
241#[cfg(test)]
242mod tests {
243 use super::*;
244
245 #[test]
246 fn test_create_profile() {
247 let mut manager = ProfileManager::new();
248 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
249
250 assert!(manager.create_profile("default", keybinds).is_ok());
251 assert_eq!(manager.len(), 1);
252 }
253
254 #[test]
255 fn test_create_duplicate_profile() {
256 let mut manager = ProfileManager::new();
257 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
258
259 manager.create_profile("default", keybinds.clone()).unwrap();
260 assert!(manager.create_profile("default", keybinds).is_err());
261 }
262
263 #[test]
264 fn test_select_profile() {
265 let mut manager = ProfileManager::new();
266 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
267
268 manager.create_profile("default", keybinds.clone()).unwrap();
269 manager.create_profile("vim", keybinds).unwrap();
270
271 assert!(manager.select_profile("vim").is_ok());
272 assert_eq!(manager.active_profile_name(), Some("vim"));
273 }
274
275 #[test]
276 fn test_delete_profile() {
277 let mut manager = ProfileManager::new();
278 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
279
280 manager.create_profile("default", keybinds.clone()).unwrap();
281 manager.create_profile("vim", keybinds).unwrap();
282
283 manager.select_profile("vim").unwrap();
284 assert!(manager.delete_profile("default").is_ok());
285 assert_eq!(manager.len(), 1);
286 }
287
288 #[test]
289 fn test_cannot_delete_active_profile() {
290 let mut manager = ProfileManager::new();
291 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
292
293 manager.create_profile("default", keybinds).unwrap();
294 assert!(manager.delete_profile("default").is_err());
295 }
296
297 #[test]
298 fn test_get_active_profile() {
299 let mut manager = ProfileManager::new();
300 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
301
302 manager.create_profile("default", keybinds).unwrap();
303 let profile = manager.get_active_profile().unwrap();
304 assert_eq!(profile.name, "default");
305 }
306
307 #[test]
308 fn test_list_profiles() {
309 let mut manager = ProfileManager::new();
310 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
311
312 manager.create_profile("default", keybinds.clone()).unwrap();
313 manager.create_profile("vim", keybinds).unwrap();
314
315 let profiles = manager.list_profiles();
316 assert_eq!(profiles.len(), 2);
317 }
318
319 #[test]
320 fn test_update_profile() {
321 let mut manager = ProfileManager::new();
322 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
323
324 manager.create_profile("default", keybinds).unwrap();
325
326 let new_keybinds = vec![
327 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
328 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
329 ];
330
331 assert!(manager.update_profile("default", new_keybinds).is_ok());
332 let profile = manager.get_profile("default").unwrap();
333 assert_eq!(profile.keybinds.len(), 2);
334 }
335
336 #[test]
337 fn test_profile_metadata_creation_time() {
338 let mut manager = ProfileManager::new();
339 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
340
341 let before_creation = SystemTime::now();
342 manager.create_profile("default", keybinds).unwrap();
343 let after_creation = SystemTime::now();
344
345 let profile = manager.get_profile("default").unwrap();
346
347 assert!(profile.created_at >= before_creation);
349 assert!(profile.created_at <= after_creation);
350
351 assert!(profile.modified_at >= before_creation);
353 assert!(profile.modified_at <= after_creation);
354 }
355
356 #[test]
357 fn test_profile_metadata_modification_time() {
358 let mut manager = ProfileManager::new();
359 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
360
361 manager.create_profile("default", keybinds).unwrap();
362 let profile_after_creation = manager.get_profile("default").unwrap();
363 let created_at = profile_after_creation.created_at;
364 let modified_at_after_creation = profile_after_creation.modified_at;
365
366 std::thread::sleep(std::time::Duration::from_millis(10));
368
369 let new_keybinds = vec![
371 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
372 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
373 ];
374
375 let before_update = SystemTime::now();
376 manager.update_profile("default", new_keybinds).unwrap();
377 let after_update = SystemTime::now();
378
379 let profile_after_update = manager.get_profile("default").unwrap();
380
381 assert_eq!(profile_after_update.created_at, created_at);
383
384 assert!(profile_after_update.modified_at >= before_update);
386 assert!(profile_after_update.modified_at <= after_update);
387 assert!(profile_after_update.modified_at > modified_at_after_creation);
388 }
389
390 #[test]
391 fn test_profile_metadata_preserved_in_name_and_keybinds() {
392 let mut manager = ProfileManager::new();
393 let keybinds = vec![
394 Keybind::new("editor.save", "Ctrl+S", "editing", "Save"),
395 Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo"),
396 ];
397
398 manager.create_profile("my_profile", keybinds.clone()).unwrap();
399
400 let profile = manager.get_profile("my_profile").unwrap();
401
402 assert_eq!(profile.name, "my_profile");
404
405 assert_eq!(profile.keybinds.len(), 2);
407 assert_eq!(profile.keybinds[0].action_id, "editor.save");
408 assert_eq!(profile.keybinds[1].action_id, "editor.undo");
409 }
410
411 #[test]
412 fn test_prevent_deletion_of_active_profile_with_metadata() {
413 let mut manager = ProfileManager::new();
414 let keybinds = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
415
416 manager.create_profile("default", keybinds).unwrap();
417
418 let profile = manager.get_profile("default").unwrap();
420 assert!(profile.created_at <= SystemTime::now());
421 assert!(profile.modified_at <= SystemTime::now());
422
423 let created_at = profile.created_at;
425 let modified_at = profile.modified_at;
426
427 assert!(manager.delete_profile("default").is_err());
429
430 let profile_after_failed_delete = manager.get_profile("default").unwrap();
432 assert_eq!(profile_after_failed_delete.created_at, created_at);
433 assert_eq!(profile_after_failed_delete.modified_at, modified_at);
434 }
435
436 #[test]
437 fn test_profile_metadata_across_multiple_profiles() {
438 let mut manager = ProfileManager::new();
439 let keybinds1 = vec![Keybind::new("editor.save", "Ctrl+S", "editing", "Save")];
440 let keybinds2 = vec![Keybind::new("editor.undo", "Ctrl+Z", "editing", "Undo")];
441
442 let before_profile1 = SystemTime::now();
443 manager.create_profile("profile1", keybinds1).unwrap();
444 let after_profile1 = SystemTime::now();
445
446 std::thread::sleep(std::time::Duration::from_millis(10));
448
449 let before_profile2 = SystemTime::now();
450 manager.create_profile("profile2", keybinds2).unwrap();
451 let after_profile2 = SystemTime::now();
452
453 let profile1 = manager.get_profile("profile1").unwrap();
454 let profile2 = manager.get_profile("profile2").unwrap();
455
456 assert!(profile1.created_at >= before_profile1);
458 assert!(profile1.created_at <= after_profile1);
459
460 assert!(profile2.created_at >= before_profile2);
462 assert!(profile2.created_at <= after_profile2);
463
464 assert!(profile2.created_at >= profile1.created_at);
466 }
467}