• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Open-S2 / gis-tools / #49

20 Apr 2025 06:40AM UTC coverage: 93.857% (-1.6%) from 95.485%
#49

push

Mr Martian
tests pass; cleanup

85383 of 90971 relevant lines covered (93.86%)

1952.78 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

98.78
/rust/data_structures/cache.rs
1
use alloc::{collections::BTreeMap, vec::Vec};
2

3
/// Function to be called when a value is deleted from the cache
4
pub type CacheDeleteFunction<K, V> = fn(&K, &V);
5

6
/// # Cache System
7
///
8
/// ## Description
9
/// A cache of values with a max size to ensure that too much old data is not stored.
10
///
11
/// ## Usage
12
///
13
/// ```rust
14
/// extern crate alloc;
15
/// use gistools::data_structures::Cache;
16
/// use alloc::borrow::ToOwned;
17
/// use alloc::string::{String, ToString};
18
///
19
/// fn on_delete(key: &String, value: &String) {
20
///     println!("Deleted key {} with value {}", key, value);
21
/// }
22
///
23
/// let mut cache = Cache::new(10, Some(on_delete));
24
/// cache.set("key".to_owned(), "value".to_owned());
25
/// println!("{:?}", cache.get(&"key".to_string())); // Some("value")
26
/// cache.delete(&"key".to_string());
27
/// ```
28
#[derive(Debug, Clone, Default)]
29
pub struct Cache<K, V>
30
where
31
    K: Ord + Clone,
32
{
33
    map: BTreeMap<K, V>,
34
    order: Vec<K>,
35
    max_size: usize,
36
    on_delete: Option<CacheDeleteFunction<K, V>>,
37
}
38

39
impl<K, V> Cache<K, V>
40
where
41
    K: Ord + Clone,
42
{
43
    /// Creates a new cache with a given max size and an optional deletion callback.
44
    pub fn new(max_size: usize, on_delete: Option<CacheDeleteFunction<K, V>>) -> Self {
7✔
45
        Self { map: BTreeMap::new(), order: Vec::new(), max_size, on_delete }
7✔
46
    }
7✔
47

48
    /// Returns the number of elements in the cache.
49
    pub fn len(&self) -> usize {
1✔
50
        self.map.len()
1✔
51
    }
1✔
52

53
    /// Returns true if the cache is empty.
54
    pub fn is_empty(&self) -> bool {
2✔
55
        self.map.is_empty()
2✔
56
    }
2✔
57

58
    /// Inserts a key-value pair into the cache.
59
    pub fn set(&mut self, key: K, value: V) {
11✔
60
        if self.map.contains_key(&key) {
11✔
61
            self.order.retain(|k| k != &key);
5✔
62
        }
10✔
63
        self.order.insert(0, key.clone());
11✔
64
        self.map.insert(key, value);
11✔
65

66
        while self.order.len() > self.max_size {
13✔
67
            if let Some(oldest) = self.order.pop() {
2✔
68
                self.delete(&oldest);
2✔
69
            }
2✔
70
        }
71
    }
11✔
72

73
    /// Retrieves a value from the cache.
74
    pub fn get(&mut self, key: &K) -> Option<&V> {
6✔
75
        if self.map.contains_key(key) {
6✔
76
            self.order.retain(|k| k != key);
8✔
77
            self.order.insert(0, key.clone());
4✔
78
        }
2✔
79
        self.map.get(key)
6✔
80
    }
6✔
81

82
    /// Retrieves a mutable value from the cache.
83
    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
1✔
84
        if self.map.contains_key(key) {
1✔
85
            self.order.retain(|k| k != key);
1✔
86
            self.order.insert(0, key.clone());
1✔
87
        }
×
88
        self.map.get_mut(key)
1✔
89
    }
1✔
90

91
    /// Removes a key from the cache.
92
    pub fn delete(&mut self, key: &K) -> bool {
5✔
93
        if let Some(value) = self.map.remove(key) {
5✔
94
            self.order.retain(|k| k != key);
12✔
95
            if let Some(ref callback) = self.on_delete {
4✔
96
                callback(key, &value);
4✔
97
            }
4✔
98
            return true;
4✔
99
        }
1✔
100
        false
1✔
101
    }
5✔
102
}
103

104
#[cfg(test)]
105
mod tests {
106
    use super::*;
107
    use alloc::{
108
        borrow::ToOwned,
109
        string::{String, ToString},
110
    };
111
    use std::println;
112

113
    #[test]
114
    fn test_cache() {
1✔
115
        fn on_delete(key: &String, value: &String) {
1✔
116
            #![allow(clippy::print_stdout)]
1✔
117
            println!("Deleted key {} with value {}", key, value);
1✔
118
        }
1✔
119

120
        let mut cache = Cache::new(5, Some(on_delete));
1✔
121
        cache.set("key".to_owned(), "value".to_owned());
1✔
122
        assert_eq!(cache.get(&"key".to_string()), Some(&"value".to_string()));
1✔
123
        // cache.delete(&"key".to_string());
124

125
        // get_mut
126
        let val = cache.get_mut(&"key".to_string()).unwrap();
1✔
127
        *val = "new value".to_owned();
1✔
128
        assert_eq!(cache.get(&"key".to_string()), Some(&"new value".to_string()));
1✔
129
        assert!(cache.delete(&"key".to_string()));
1✔
130

131
        // delete non-existant
132
        assert!(!cache.delete(&"key".to_string()));
1✔
133
    }
1✔
134

135
    #[test]
136
    fn test_cache_overflow() {
1✔
137
        fn on_delete(key: &i32, value: &i32) {
3✔
138
            #![allow(clippy::print_stdout)]
3✔
139
            println!("Deleted key {} with value {}", key, value);
3✔
140
        }
3✔
141

142
        let mut cache = Cache::<i32, i32>::new(5, Some(on_delete)); // Cache::new(5, None);
1✔
143
        assert!(cache.is_empty());
1✔
144

145
        cache.set(1, 2);
1✔
146
        assert_eq!(cache.get(&1), Some(&2));
1✔
147
        assert!(cache.delete(&1));
1✔
148

149
        cache.set(1, 2);
1✔
150
        cache.set(2, 3);
1✔
151
        cache.set(3, 4);
1✔
152
        cache.set(4, 5);
1✔
153
        cache.set(5, 6);
1✔
154
        cache.set(6, 7);
1✔
155
        cache.set(7, 8);
1✔
156
        cache.set(4, 9);
1✔
157

1✔
158
        assert_eq!(cache.len(), 5);
1✔
159
        assert!(!cache.is_empty());
1✔
160
        assert_eq!(cache.get(&2), None);
1✔
161
        assert_eq!(cache.get(&3), Some(&4));
1✔
162
    }
1✔
163
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc