You've already forked rust-tutor
generic types, traits and lifetimes
- get claude to create rustlings style exercises based on chapter 10 of the book - update CLAUDE.md to prevent it from producing incorrect exercises - complete exercises/01-generic-cache-system
This commit is contained in:
112
exercises/01-generic-cache-system/src/main.rs
Normal file
112
exercises/01-generic-cache-system/src/main.rs
Normal file
@@ -0,0 +1,112 @@
|
||||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
fn cache_get<K: Eq + Hash, V>(map: &HashMap<K, V>, key: K) -> Option<&V> {
|
||||
for (k, v) in map.iter() {
|
||||
if *k == key {
|
||||
return Some(&v);
|
||||
}
|
||||
}
|
||||
return None;
|
||||
}
|
||||
|
||||
fn cache_insert<K: Eq + Hash, V: Copy>(cache: &mut HashMap<K, V>, key: K, value: V) -> Option<V> {
|
||||
for (k, v) in cache.iter() {
|
||||
let return_value = *v;
|
||||
if *k == key {
|
||||
//update value
|
||||
cache.insert(key, value);
|
||||
}
|
||||
//"there was an existing record with this key which we wrote over"
|
||||
//"and the key we wrote over was return_value"
|
||||
return Some(return_value);
|
||||
}
|
||||
// insert new value
|
||||
cache.insert(key, value);
|
||||
// "there wasnt an existing record with this key"
|
||||
return None;
|
||||
}
|
||||
|
||||
fn cache_compute_if_absent<K: Eq + Hash, V, F>(cache: &mut HashMap<K, V>, key: K, compute: F) -> &V
|
||||
where
|
||||
F: Fn() -> V,
|
||||
{
|
||||
cache.entry(key).or_insert_with(compute)
|
||||
}
|
||||
|
||||
fn batch_lookup<'a, K: Eq + Hash, V>(cache: &'a HashMap<K, V>, keys: &[K]) -> Vec<&'a V> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
for key in keys {
|
||||
if let Some(value) = cache.get(key) {
|
||||
result.push(value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("let's go!");
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_cache_get_found() {
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert("key1", 42);
|
||||
assert_eq!(cache_get(&cache, &"key1"), Some(&42));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_get_missing() {
|
||||
let cache: HashMap<&str, i32> = HashMap::new();
|
||||
assert_eq!(cache_get(&cache, &"missing"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_insert_new() {
|
||||
let mut cache = HashMap::new();
|
||||
assert_eq!(cache_insert(&mut cache, "new", 100), None);
|
||||
assert_eq!(cache.get("new"), Some(&100));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cache_insert_existing() {
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert("key", 50);
|
||||
assert_eq!(cache_insert(&mut cache, "key", 75), Some(50));
|
||||
assert_eq!(cache.get("key"), Some(&75));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_if_absent_missing() {
|
||||
let mut cache = HashMap::new();
|
||||
let result = cache_compute_if_absent(&mut cache, "compute", || "computed".to_string());
|
||||
assert_eq!(result, &"computed".to_string());
|
||||
assert_eq!(cache.get("compute"), Some(&"computed".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_compute_if_absent_exists() {
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert("existing", "original".to_string());
|
||||
let result =
|
||||
cache_compute_if_absent(&mut cache, "existing", || "should not run".to_string());
|
||||
assert_eq!(result, &"original".to_string());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_batch_lookup() {
|
||||
let mut cache = HashMap::new();
|
||||
cache.insert(1, "one");
|
||||
cache.insert(3, "three");
|
||||
cache.insert(5, "five");
|
||||
|
||||
let keys = [1, 2, 3, 4, 5];
|
||||
let results = batch_lookup(&cache, &keys);
|
||||
assert_eq!(results, vec![&"one", &"three", &"five"]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user