gs_rust_cache/
lib.rs

1//! Thread safe cache developed using [lru crate](https://crates.io/crates/lru) as its core. 
2//! Supports LRU, positive and negative TTLs and miss handler function.
3//! It is intended to be used using the function `retrieve_or_compute`, which will return the value if it is in the cache,
4//! or compute it using the miss_handler function if it is not.
5//!
6//! ## Example
7//!
8//! ```rust
9//! extern crate gs_rust_cache;
10//! use gs_rust_cache::Cache;
11//! use std::any::Any;
12//! use std::time::Duration;
13//!
14//!fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
15//!    // Your Code Here
16//!    *data = 123;
17//!    *adhoc_code = 200;
18//!    true
19//! }
20//! 
21//! fn main() {
22//!     let mut cache = Cache::new(
23//!         3,
24//!         miss_handler,
25//!         Duration::from_millis(200),          
26//!         Duration::from_millis(100),          
27//!     );
28//! 
29//!     let key =  456;
30//!     let (value, adhoc_code, is_hit) = cache.retrieve_or_compute(&key); // first one is calculated
31//!     let (value_1, adhoc_code_1, is_hit_1) = cache.retrieve_or_compute(&key); // afterwards it is retrieved
32//! 
33//!     assert_eq!(value, value_1);
34//!     assert_eq!(adhoc_code, adhoc_code_1);
35//!     assert!(is_hit); // is_hit is false because the value was computed
36//!     assert!(is_hit_1); // is_hit_1 is true because the value was retrieved from the cache
37//! 
38//! }
39//! ```
40
41use lru::{LruCache, DefaultHasher};
42use std::hash::Hash;
43use std::num::NonZeroUsize;
44use std::ops::DerefMut;
45use std::time::{Duration, Instant};
46use std::sync::{Arc, Condvar, Mutex};
47use std::any::Any;
48
49#[derive(Debug, PartialEq, Clone, Copy)]
50enum EntryStatus {
51    AVAILABLE,
52    CALCULATING,
53    READY,
54    FAILED,
55}
56
57#[derive(Debug, Clone)]
58struct Entry<D> {
59    data: D,
60    adhoc_code: u8,
61    expiration: Instant,
62    status: EntryStatus,
63    cond_var: Arc<Condvar>
64}
65
66impl<D: PartialEq> PartialEq for Entry<D> {
67    fn eq(&self, other: &Self) -> bool {
68        self.data == other.data &&
69        self.adhoc_code == other.adhoc_code &&
70        self.expiration == other.expiration &&
71        self.status == other.status
72    }
73}
74
75
76impl<D: Default> Entry<D> {
77
78    fn default() -> Self {
79        Entry {
80            data: Default::default(),
81            expiration: Instant::now(),
82            adhoc_code: 0,
83            status: EntryStatus::AVAILABLE,
84            cond_var: Arc::new(Condvar::new())
85        }
86    }
87
88
89    fn new(data: D, expiration: Instant, adhoc_code: u8) -> Self {
90        Entry {
91            data,
92            expiration,
93            adhoc_code,
94            status: EntryStatus::AVAILABLE,
95            cond_var: Arc::new(Condvar::new())
96        }
97    }
98
99    fn is_valid(&self) -> bool {
100        self.expiration > Instant::now()
101    }
102
103}
104
105pub type MissHandler<K, D> = fn(&K, &mut D, &mut u8, &[&dyn Any]) -> bool;
106
107pub struct Cache<K, D> {
108    lru_cache: Arc<Mutex<LruCache<K, Arc<Mutex<Entry<D>>>>>>,
109    miss_handler: MissHandler<K, D>,
110    positive_ttl: Duration, // seconds
111    negative_ttl: Duration, // seconds
112}
113
114impl<K: Eq + Hash + Clone, D: Default + Clone> Cache<K, D> {
115    pub fn new(
116        size: usize,
117        miss_handler: MissHandler<K, D>,
118        positive_ttl: Duration,
119        negative_ttl: Duration,
120    ) -> Self {
121        let hash_builder = DefaultHasher::default();
122        Cache {
123            lru_cache: Arc::new(Mutex::new(LruCache::with_hasher(
124                NonZeroUsize::new(size).unwrap(),
125                hash_builder,
126            ))),
127            miss_handler,
128            positive_ttl,
129            negative_ttl,
130        }
131    }
132
133    pub fn insert(&self, key: &K, data: D) {
134        let expiration = Instant::now() + self.positive_ttl;
135        let entry = Entry::new(data, expiration, 0);
136        let entry_arc = Arc::new(Mutex::new(entry));
137        self.lru_cache.lock().unwrap().put(key.clone(), entry_arc);     
138    }
139
140    pub fn get(&self, key: &K) -> Option<D> {
141        if let Some(entry_arc) = self.get_entry(&key) {
142            let entry = entry_arc.lock().unwrap();
143            return Some(entry.data.clone());
144        }
145        None
146    }
147
148    fn get_entry(&self, key: &K) -> Option<Arc<Mutex<Entry<D>>>> {
149        // lock the cache
150        let cache_entry = {
151            let mut cache = self.lru_cache.lock().unwrap();
152            cache.get(key).map(|entry| Arc::clone(entry))
153        };
154        // check if the entry exists and is valid
155        match cache_entry {
156            None => return None,
157            Some(entry_arc) => {
158                let entry = entry_arc.lock().unwrap();
159                if entry.is_valid() {
160                    return Some(Arc::clone(&entry_arc));
161                }
162            }            
163        }
164        // if the entry is not valid or does not exist, remove it
165        self.lru_cache.lock().unwrap().pop(key);
166        None
167    }
168
169    pub fn len(&self) -> usize {
170        self.lru_cache.lock().unwrap().len()
171    }
172
173    fn handle_hit(&self, key: &K) -> Option<(D, u8)> {
174        // check if the the entry exists and is valid
175        if let Some(entry_arc) = self.get_entry(key) {
176            let entry_arc_clone = Arc::clone(&entry_arc);
177            let entry = entry_arc.lock().unwrap();
178            match entry.status {
179                EntryStatus::AVAILABLE => {
180                    // should not happen
181                    eprintln!("Error: entry should not be available at this point");
182                    return None;
183                }
184                EntryStatus::CALCULATING => {
185                    println!("CALCULATING");
186                    match entry.cond_var.wait_while(
187                        entry_arc_clone.lock().unwrap(), 
188                        |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
189                        {
190                            Ok(_) => {}
191                            Err(e) => {
192                                eprintln!("Error while waiting: {:?}", e);
193                                return None;
194                            }
195                        }
196                }
197                _ => {}
198            }
199            return Some((entry.data.clone(), entry.adhoc_code));
200        }
201        return None;
202    }
203
204    pub fn retrieve_or_compute(&self, key: &K) -> Option<(D, u8, bool)> {
205        self.retrieve_or_compute_with_params(key, &[])
206    }
207
208    pub fn retrieve_or_compute_with_params(&self, key: &K, params: &[&dyn Any]) -> Option<(D, u8, bool)> {
209        let miss_handler = self.miss_handler;
210        let positive_ttl = self.positive_ttl;
211        let negative_ttl = self.negative_ttl;
212
213        if let Some((data, adhoc_code)) = self.handle_hit(&key) {
214            return Some((data, adhoc_code, true));
215        }
216
217        // Miss
218        let entry_arc = {
219            let mut locked_cache = self.lru_cache.lock().unwrap();
220            let entry_arc = locked_cache.get_or_insert_mut(key.clone(), || Arc::new(Mutex::new(Entry::default())));
221            Arc::clone(&entry_arc)
222        };
223
224        let mut locked_entry = entry_arc.lock().unwrap();
225        let entry_arc_clone = Arc::clone(&entry_arc);
226        let locked_entry = locked_entry.deref_mut();
227
228        match locked_entry.status {
229            EntryStatus::AVAILABLE => {
230                {
231                    locked_entry.status = EntryStatus::CALCULATING;
232                    if miss_handler(&key, &mut locked_entry.data, &mut locked_entry.adhoc_code, params) {
233                        locked_entry.expiration = Instant::now() + positive_ttl;
234                        locked_entry.status = EntryStatus::READY;
235                    } else {
236                        locked_entry.expiration = Instant::now() + negative_ttl;
237                        locked_entry.status = EntryStatus::FAILED;
238                    }
239                }
240                locked_entry.cond_var.notify_all();
241            }
242            EntryStatus::CALCULATING => {
243                println!("CALCULATING");
244                match locked_entry.cond_var.wait_while(
245                    entry_arc_clone.lock().unwrap(), 
246                    |entry: &mut Entry<D>| entry.status == EntryStatus::CALCULATING)
247                    {
248                        Ok(_) => {}
249                        Err(e) => {
250                            eprintln!("Error while waiting: {:?}", e);
251                            return None;
252                        }
253                    }
254            }
255            EntryStatus::READY | EntryStatus::FAILED => {}
256        }
257        
258        
259        Some((locked_entry.data.clone(), locked_entry.adhoc_code, false))
260    }
261}
262
263// ===============================================================
264// =============================TESTS=============================
265// ===============================================================
266
267#[cfg(test)]
268mod tests {
269
270    use std::thread;
271
272    use super::*;
273    use rstest::*;
274
275    #[fixture]
276    fn simple_cache() -> Cache<i32, i32> {
277        fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
278            // FAIL if key is -1
279            if *key == -1 {
280                return false
281            }
282            *data = key * 2;
283            *adhoc_code += 1; // should always be 1
284            true
285        }
286        Cache::new(
287            3,
288            miss_handler,
289            Duration::from_millis(200),          
290            Duration::from_millis(100),          
291        )
292    }
293
294    #[rstest]
295    fn insert_value(simple_cache: Cache<i32, i32>) {
296        // Arrange
297        let key = 1;
298        let value = 2;
299
300        // Act
301        simple_cache.insert(&key, value);
302
303        // Assert
304        assert_eq!(simple_cache.len(), 1);
305    }
306
307    #[rstest]
308    fn insert_same_key(simple_cache: Cache<i32, i32>) {
309        // Arrange
310        let key = 1;
311        let value = 2;
312
313        // Act
314        simple_cache.insert(&key, value);
315        simple_cache.insert(&key, value);
316
317        // Assert
318        assert_eq!(simple_cache.len(), 1);
319    }
320
321    #[rstest]
322    fn get_value(simple_cache: Cache<i32, i32>) {
323        // Arrange
324        let key = 1;
325        let value = 2;
326
327        // Act
328        simple_cache.insert(&key, value);
329
330        // Assert
331        assert_eq!(simple_cache.get(&key), Some(value));
332    }
333
334    #[rstest]
335    fn get_value_not_found(simple_cache: Cache<i32, i32>) {
336        // Arrange
337        let key = 1;
338
339        // Assert
340        assert_eq!(simple_cache.get(&key), None);
341    }
342
343    #[rstest]
344    fn insert_max_capacity(simple_cache: Cache<i32, i32>) {
345        // Arrange
346        let key1 = 1;
347        let key2 = 2;
348        let key3 = 3;
349        let key4 = 4;
350        let value = 2;
351
352        // Act
353        simple_cache.insert(&key1, value);
354        simple_cache.insert(&key2, value);
355        simple_cache.insert(&key3, value);
356        simple_cache.insert(&key4, value);
357
358        // Assert
359        assert_eq!(simple_cache.len(), 3);
360        assert_eq!(simple_cache.get(&key1), None); // lru is removed
361    }
362
363    #[rstest]
364    fn get_lru_change(simple_cache: Cache<i32, i32>) {
365        // Arrange
366        let key1 = 1;
367        let key2 = 2;
368        let key3 = 3;
369        let key4 = 4;
370        let value = 2;
371
372        // Act
373        simple_cache.insert(&key1, value);
374        simple_cache.insert(&key2, value);
375        simple_cache.get(&key1); // key2 is now the lru
376        simple_cache.insert(&key3, value);
377        simple_cache.insert(&key4, value);
378
379        // Assert
380        assert_eq!(simple_cache.len(), 3);
381        assert_eq!(simple_cache.get(&key2), None); // lru is removed
382    }
383
384    #[rstest]
385    fn ttl_expired(simple_cache: Cache<i32, i32>) {
386        // Arrange
387        let key = 1;
388        let value = 2;
389
390        // Act
391        simple_cache.insert(&key, value);
392        std::thread::sleep(std::time::Duration::from_millis(250));
393
394        // Assert
395        assert_eq!(simple_cache.get(&key), None);
396    }
397
398    #[rstest]
399    fn retrieve_or_compute_not_in_cache(simple_cache: Cache<i32, i32>){
400        // Arrange
401        let key = 1;
402
403        // Act
404        let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
405
406        // Assert
407        assert_eq!(data, 2);
408        assert_eq!(adhoc_code, 1);
409        assert_eq!(is_hit, false);
410        assert_eq!(simple_cache.len(), 1);
411    }
412
413    #[rstest]
414    fn retrieve_or_compute_already_in_cache(simple_cache: Cache<i32, i32>){
415        // Arrange
416        let key = 1;
417
418        // Act
419        simple_cache.retrieve_or_compute(&key);
420        simple_cache.retrieve_or_compute(&key);
421        simple_cache.retrieve_or_compute(&key);
422        simple_cache.retrieve_or_compute(&key);
423        let (data, adhoc_code, is_hit) = simple_cache.retrieve_or_compute(&key).unwrap();
424
425        // Assert
426        assert_eq!(data, 2);
427        assert_eq!(adhoc_code, 1);
428        assert_eq!(is_hit, true);
429        assert_eq!(simple_cache.len(), 1);
430    }
431
432    #[rstest]
433    fn retrieve_or_compute_ttl_expired(simple_cache: Cache<i32, i32>){
434        // Arrange
435        let key = 1;
436        // Act
437        simple_cache.retrieve_or_compute(&key);
438        let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
439        std::thread::sleep(std::time::Duration::from_millis(100));
440        simple_cache.retrieve_or_compute(&key);
441        let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
442        std::thread::sleep(std::time::Duration::from_millis(150));
443        simple_cache.retrieve_or_compute(&key);
444        let entry_3 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
445        
446        // Assert
447        assert_eq!(entry_1.status, EntryStatus::READY);
448        assert_eq!(entry_1, entry_2); // not expired
449        assert_ne!(entry_1, entry_3); // expired 
450    }
451
452    #[rstest]
453    fn retrieve_or_compute_negative_ttl(simple_cache: Cache<i32, i32>){
454        // Arrange
455        let key = -1;
456
457        // Act
458        simple_cache.retrieve_or_compute(&key);
459        let entry_1 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
460        std::thread::sleep(std::time::Duration::from_millis(105));
461        simple_cache.retrieve_or_compute(&key);
462        let entry_2 = simple_cache.lru_cache.lock().unwrap().peek(&key).unwrap().lock().unwrap().clone();
463        
464        // Assert
465        assert_ne!(entry_1, entry_2); // expired because negative ttl is lower
466        assert_eq!(entry_1.status, EntryStatus::FAILED);
467    }
468
469    #[fixture]
470    fn simple_cache_with_params () -> Cache<i32, i32> {
471        fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, params: &[&dyn Any]) -> bool {
472            
473            // FAIL if key is -1
474            if *key == -1 {
475                return false
476            }
477            *data = key * 2;
478            for param in params {
479                if let Some(param) = param.downcast_ref::<i32>() {
480                    *data += param;
481                }
482            }
483            if params[0].downcast_ref::<&str>().is_some() {
484                *adhoc_code += 1;
485            }
486            *adhoc_code += 1; // should always be 1
487            true
488        }
489        Cache::new(
490            3,
491            miss_handler,
492            Duration::from_millis(200),          
493            Duration::from_millis(100),          
494        )
495    }
496
497    #[rstest]
498    fn retrieve_or_compute_with_params(simple_cache_with_params: Cache<i32, i32>){
499        // Arrange
500        let key = 1;
501        let param = 3;
502
503        // Act
504        let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[&param]).unwrap();
505
506        // Assert
507        assert_eq!(data, 5);
508        assert_eq!(adhoc_code, 1);
509        assert_eq!(is_hit, false);
510        assert_eq!(simple_cache_with_params.len(), 1);
511    }
512
513    #[rstest]
514    fn retrieve_or_compute_with_multiple_params(simple_cache_with_params: Cache<i32, i32>){
515        // Arrange
516        let key = 1;
517        let param1 = 3;
518        let param2 = 4;
519
520        // Act
521        let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[&param1, &param2]).unwrap();
522
523        // Assert
524        assert_eq!(data, 9);
525        assert_eq!(adhoc_code, 1);
526        assert_eq!(is_hit, false);
527        assert_eq!(simple_cache_with_params.len(), 1);
528    }
529    
530    #[rstest]
531    fn retrieve_or_compute_with_multiple_params_different_types(simple_cache_with_params: Cache<i32, i32>){
532        // Arrange
533        let key = 1;
534        let param1 = "hola";
535        let param2 = 3;
536        let param3 = 4;
537
538        // Act
539        let (data, adhoc_code, is_hit) = simple_cache_with_params.retrieve_or_compute_with_params(&key, &[&param1, &param2, &param3]).unwrap();
540
541        // Assert
542        assert_eq!(data, 9);
543        assert_eq!(adhoc_code, 2);
544        assert_eq!(is_hit, false);
545        assert_eq!(simple_cache_with_params.len(), 1);
546    }
547
548    #[fixture]
549    fn time_consuming_mh() -> Cache<i32, i32> {
550        fn miss_handler(key: &i32, data: &mut i32, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
551
552            std::thread::sleep(std::time::Duration::from_millis(500));
553            if *key == 3 {
554                std::thread::sleep(std::time::Duration::from_millis(500));
555            }
556
557            *data = key * 2;
558            *adhoc_code += 1; // should always be 1
559            true
560        }
561        Cache::new(
562            200,
563            miss_handler,
564            Duration::from_secs(60),          
565            Duration::from_secs(60),          
566        )
567    }
568
569    #[rstest]
570    fn test_thread_safe_cache_same_key(time_consuming_mh: Cache<i32, i32>) {        
571        // Arrange            
572        let cache = Arc::new(time_consuming_mh);
573        let n_threads: i32 = 200;
574        let start = Instant::now();
575
576        // Act
577        let handles: Vec<_> = (0..n_threads).map(|i| {
578            let cache_clone = Arc::clone(&cache);
579            thread::spawn({
580                move || {
581                    let key = 456;
582                    let start = Instant::now();
583                    let res = cache_clone.retrieve_or_compute(&key);
584                    (res, start.elapsed())
585                }
586            })
587        }).collect();
588
589        // Assert
590        let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
591        let duration = start.elapsed();
592        for res in results {
593            // assert res is ok
594            assert!(res.is_ok());
595            if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
596                let key = 456;
597                assert_eq!(*data, key * 2);
598                assert_eq!(*adhoc_code, 1);
599                assert!(elapsed.as_millis() < 600);
600            }
601        }        
602        
603        assert!(cache.len() == 1);
604        assert!(duration.as_secs() < 1);
605        
606    }
607
608    #[rstest]
609    fn test_thread_safe_cache_different_keys(time_consuming_mh: Cache<i32, i32>) {
610        // Arrange
611        let cache = Arc::new(time_consuming_mh);
612        let n_threads = 20;
613        let start = Instant::now();
614
615        // Act
616        let handles: Vec<_> = (0..n_threads).map(|i| {
617            let cache_clone = Arc::clone(&cache);
618            thread::spawn({
619                move || {
620                    let key = 456 + i as i32;
621                    let start = Instant::now();
622                    let res = cache_clone.retrieve_or_compute(&key);
623                    (res, start.elapsed())
624                }
625            })
626        }).collect();
627let results: Vec<_> = handles.into_iter().map(|handle| handle.join()).collect();
628        
629        let duration = start.elapsed();
630        // Assert
631        for i in 0..n_threads {
632            let res = &results[i];
633            // assert res is ok
634            assert!(res.is_ok());
635            if let (Some((data, adhoc_code, _)), elapsed) = res.as_ref().unwrap() {
636                let key = 456 + i as i32;
637                assert_eq!(*data, key * 2);
638                assert_eq!(*adhoc_code, 1);
639                assert!(elapsed.as_millis() < 600);
640            }
641        }      
642        for i in 0..n_threads {
643            let key = 456 + i as i32;
644            let data = cache.get(&key);
645            assert_eq!(data, Some(key * 2));
646        }
647        assert!(cache.len() == n_threads.try_into().unwrap());
648        assert!(duration.as_secs() < 1);
649    }
650
651    #[rstest]
652    fn test_thread_safe_cache_maximum_capacity(time_consuming_mh: Cache<i32, i32>) {
653        // Arrange
654        let cache = Arc::new(time_consuming_mh);
655        let n_threads = 202;
656        let start = Instant::now();
657
658        // Act
659        let handles: Vec<_> = (0..n_threads).map(|i| {
660            let cache_clone = Arc::clone(&cache);
661            thread::spawn(move || {
662                let key = 456 + i;
663                cache_clone.retrieve_or_compute(&key);
664            })
665        }).collect();
666
667        for handle in handles {
668            let res = handle.join();
669            // assert res is ok
670            assert!(res.is_ok());
671            res.unwrap();
672        }
673
674        // Assert
675        let mut not_in_cache_count = 0;      
676        for i in 0..n_threads {
677            let key = 456 + i;
678            let data = cache.get(&key);
679            if data == None {
680                not_in_cache_count += 1;
681            } else {
682                let key = 456 + i;
683                let data = cache.get(&key);
684                assert_eq!(data, Some(key * 2));
685            }
686        }
687        let duration = start.elapsed();
688        assert!(cache.len() == 200);
689        assert!(duration.as_secs() < 1);
690        assert_eq!(not_in_cache_count, 2);
691    }
692
693    #[rstest]
694    fn test_thread_safe_heavy_threads(time_consuming_mh: Cache<i32, i32>) {
695        let cache = Arc::new(time_consuming_mh);
696        for cicle in 0..50 {
697            // Arrange
698            let n_keys = 5;
699            let entries_per_key = 20;
700            let results = vec![((0,0), Duration::default()); n_keys * entries_per_key];
701            let results_arc = Arc::new(Mutex::new(results));
702            let mut threads = Vec::<thread::JoinHandle<_>>::with_capacity(n_keys * entries_per_key);
703
704            // Act
705            for i in 0..n_keys {
706                for j in 0..entries_per_key {
707                    let cache_clone = Arc::clone(&cache);
708                    let results_clone = Arc::clone(&results_arc);
709                    threads.push(thread::spawn(move || {
710                        let key = (i + 1) as i32;
711                        let start = Instant::now();
712                        let (data, adhoc_code, _) = cache_clone.retrieve_or_compute(&key).unwrap();
713                        let mut results = results_clone.lock().unwrap();
714                        results[i*entries_per_key+j] = ((data, adhoc_code), start.elapsed());
715                    }));
716                }
717            }
718            for handle in threads {
719                let res = handle.join();
720                // assert res is ok
721                assert!(res.is_ok());
722                res.unwrap();
723            }
724
725            // Assert
726            let mut key = 0;
727            for i in (0..n_keys * entries_per_key).step_by(entries_per_key) {
728                key += 1;
729                let results = results_arc.lock().unwrap();
730                let (res_i, elapsed_i) = results[i];
731                for j in 1..entries_per_key {
732                    let (res_j, elapsed_j) = results[i+j];
733                    assert_eq!(res_i, res_j);
734                    println!("key : {} i: {} j: {}", key,  elapsed_i.as_millis(), elapsed_j.as_millis());
735                    if cicle ==0 && key == 3 {                        
736                        assert!(elapsed_i.as_millis() > 600);
737                        assert!(elapsed_j.as_millis() > 600);
738                    } else {
739                        assert!(elapsed_i.as_millis() < 600);
740                        assert!(elapsed_j.as_millis() < 600);
741                    }
742
743                }
744            }
745            assert!(cache.len() == n_keys);
746        }
747    }
748
749    #[derive(Debug, PartialEq, Eq, Clone, Hash, Copy, Default)]
750    struct SimpleStruct {
751        value: i32,
752    }
753    #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
754    struct ComplexKey {
755        id: i32,
756        name: String,
757        nested: SimpleStruct,
758        array: Vec<i32>,
759
760    }
761
762  #[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
763    struct ComplexData {
764        value: i32,
765        description: String,
766        nested: SimpleStruct,
767        array: Vec<i32>,
768    }
769
770    #[fixture]
771    fn complex_key_and_data_cache() -> Cache<ComplexKey, ComplexData> {
772        fn miss_handler(key: &ComplexKey, data: &mut ComplexData, adhoc_code: &mut u8, _: &[&dyn Any]) -> bool {
773            // wait 500 ms
774            std::thread::sleep(std::time::Duration::from_millis(500));
775            // FAIL if key.id is -1
776            if key.id == -1 {
777                return false
778            }
779            data.value = key.id * 2;
780            data.description = key.name.clone();
781            data.nested = key.nested.clone();
782            data.array = key.array.clone();
783            *adhoc_code += 1; // should always be 1
784            true
785        }
786        Cache::new(
787            200,
788            miss_handler,
789            Duration::from_secs(1),          
790            Duration::from_secs(1),          
791        )
792    }
793
794    #[rstest]
795    fn complex_key_and_data_cache_insert(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
796        // Arrange
797        let key = ComplexKey {
798            id: 1,
799            name: "name".to_string(),
800            nested: SimpleStruct { value: 1 },
801            array: vec![1, 2, 3],
802        };
803        let data = ComplexData {
804            value: 2,
805            description: "name".to_string(),
806            nested: SimpleStruct { value: 1 },
807            array: vec![1, 2, 3],
808        };
809
810        // Act
811        complex_key_and_data_cache.insert(&key, data);
812
813        // Assert
814        assert_eq!(complex_key_and_data_cache.len(), 1);
815    }
816
817    #[rstest]
818    fn complex_key_data_retrieve_or_compute(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
819        // Arrange
820        let key = ComplexKey {
821            id: 1,
822            name: "name".to_string(),
823            nested: SimpleStruct { value: 1 },
824            array: vec![1, 2, 3],
825        };
826
827        // Act
828        let (data, adhoc_code, is_hit) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
829
830        // Assert
831        assert_eq!(data.value, 2);
832        assert_eq!(data.description, "name");
833        assert_eq!(data.nested, SimpleStruct { value: 1 });
834        assert_eq!(data.array, vec![1, 2, 3]);
835        assert_eq!(adhoc_code, 1);
836        assert_eq!(is_hit, false);
837        assert_eq!(complex_key_and_data_cache.len(), 1);    
838    }
839
840    #[rstest]
841    fn complex_key_data_retrieve_or_compute_change_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
842        // Arrange
843        let key = ComplexKey {
844            id: 1,
845            name: "name".to_string(),
846            nested: SimpleStruct { value: 1 },
847            array: vec![1, 2, 3],
848        };
849        let key_clone = key.clone();
850        let mut key_change = key.clone();
851        key_change.id = 2;
852
853        // Act
854        let (data, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key).unwrap();
855        let (data1, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_clone).unwrap();
856        let (data2, _, _) = complex_key_and_data_cache.retrieve_or_compute(&key_change).unwrap();
857
858        // Assert
859        assert_eq!(data, data1);
860        assert_ne!(data, data2);
861        assert_eq!(complex_key_and_data_cache.len(), 2);
862    }
863
864    #[rstest]
865    fn complex_key_data_thread_safe_cache_same_key(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
866        // Arrange
867        let cache = Arc::new(complex_key_and_data_cache);
868        let n_threads: i32 = 200;
869        let start = Instant::now();
870        let key = ComplexKey {
871            id: 1,
872            name: "name".to_string(),
873            nested: SimpleStruct { value: 1 },
874            array: vec![1, 2, 3],
875        };
876
877        // Act
878        let handles: Vec<_> = (0..n_threads).map(|i| {
879            let cache_clone = Arc::clone(&cache);
880            thread::Builder::new().name(format!("Thread {}", i)).spawn({
881            let value = key.clone();
882            move || {
883            cache_clone.retrieve_or_compute(&value)
884            }
885            })
886        }).collect();
887
888        // Assert
889        let results = handles.into_iter().map(|handle| handle.unwrap().join());
890        let mut i = 0;
891        for res in results {
892            // assert res is ok
893            assert!(res.is_ok());
894            if let Some((data, adhoc_code, is_hit)) = res.unwrap() {
895                assert_eq!(data.value, 2);
896                assert_eq!(data.description, "name");
897                assert_eq!(data.nested, SimpleStruct { value: 1 });
898                assert_eq!(data.array, vec![1, 2, 3]);
899                assert_eq!(adhoc_code, 1);
900                if i == 0 {
901                     assert!(!is_hit);
902                }else {
903                    assert!(is_hit);
904                }
905            }
906            i += 1;
907        }        
908        let duration = start.elapsed();
909        assert!(cache.len() == 1);
910        assert!(duration.as_secs() < 1);
911        
912    }
913
914    #[rstest]
915    fn complex_key_data_thread_safe_cache_different_keys(complex_key_and_data_cache: Cache<ComplexKey, ComplexData>) {
916        // Arrange
917        let cache = Arc::new(complex_key_and_data_cache);
918        let n_threads = 200;
919        let start = Instant::now();
920
921        // Act
922        let handles: Vec<_> = (0..n_threads).map(|i| {
923            let cache_clone = Arc::clone(&cache);
924            let key: ComplexKey = ComplexKey {
925                id: 1 + i,
926                name: "name".to_string(),
927                nested: SimpleStruct { value: 1 },
928                array: vec![1, 2, 3],
929            };
930            thread::spawn({ move || {
931            cache_clone.retrieve_or_compute(&key)
932            }
933            })
934        }).collect();
935
936        for handle in handles {
937            let res = handle.join();
938            // assert res is ok
939            assert!(res.is_ok());
940            res.unwrap();
941        }
942
943        // Assert        
944        for i in 0..n_threads {
945            let key = ComplexKey {
946                id: 1 + i,
947                name: "name".to_string(),
948                nested: SimpleStruct { value: 1 },
949                array: vec![1, 2, 3],
950            };
951            let data = cache.get(&key);
952
953            assert_eq!(data, Some(ComplexData {
954                value: (1 + i) * 2,
955                description: "name".to_string(),
956                nested: SimpleStruct { value: 1 },
957                array: vec![1, 2, 3],
958            }));
959        }
960        assert!(cache.len() == n_threads.try_into().unwrap());
961        let duration = start.elapsed();
962        assert!(duration.as_secs() < 1);
963    }
964
965
966}