tinylfu-cached 0.0.4

High performance, LFU based in-memory cache.
Documentation
use std::sync::Arc;

use tinylfu_cached::cache::cached::CacheD;
use tinylfu_cached::cache::config::ConfigBuilder;

#[tokio::test]
async fn get_values_for_an_existing_keys() {
    let cached = CacheD::new(ConfigBuilder::new(1000, 100, 1000).build());
    let cached = Arc::new(cached);

    let mut handles = Vec::new();
    let readonly_cache = cached.clone();

    for task_id in 1..=5 {
        let cached = cached.clone();
        let future = async move {
            let mut start_index = task_id * 10;
            let end_index = start_index + 10;

            while start_index < end_index {
                cached.put_with_weight(start_index, start_index, 20).unwrap().handle().await;
                start_index += 1;
            }
        };
        handles.push(tokio::spawn(future));
    };
    for handle in handles {
        handle.await.unwrap();
    }

    for index in 10..60 {
        let value = readonly_cache.get(&index);
        assert_eq!(Some(index), value);
    }
    assert_eq!(1000, readonly_cache.total_weight_used());
}

#[tokio::test]
async fn put_key_values_given_cache_weight_is_reached() {
    let cached = CacheD::new(ConfigBuilder::new(1000, 100, 980).build());
    let cached = Arc::new(cached);

    let mut handles = Vec::new();
    let clone = cached.clone();

    for task_id in 1..=5 {
        let cached = cached.clone();
        let future = async move {
            let mut start_index = task_id * 10;
            let end_index = start_index + 10;

            while start_index < end_index {
                cached.put_with_weight(start_index, start_index, 20).unwrap().handle().await;
                start_index += 1;
            }
        };
        handles.push(tokio::spawn(future));
    };

    for handle in handles {
        handle.await.unwrap();
    }

    assert_eq!(980, clone.total_weight_used());
}

#[tokio::test]
async fn ensure_that_the_weight_of_the_cache_does_not_go_beyond_the_total_weight() {
    let cached = CacheD::new(ConfigBuilder::new(1000, 100, 9500).build());
    let cached = Arc::new(cached);

    let mut handles = Vec::new();
    let readonly_cache = cached.clone();

    for task_id in 1..=1000 {
        let cached = cached.clone();
        let future = async move {
            let mut start_index = task_id * 10;
            let end_index = start_index + 10;

            while start_index < end_index {
                cached.put_with_weight(start_index, start_index, 10).unwrap().handle().await;
                start_index += 1;
            }
        };
        handles.push(tokio::spawn(future));
    };
    for handle in handles {
        handle.await.unwrap();
    }
    assert_eq!(9500, readonly_cache.total_weight_used());
}

#[tokio::test]
async fn put_delete_and_get() {
    let cached = Arc::new(CacheD::new(ConfigBuilder::new(1000, 100, 2000).build()));
    let put_cached = cached.clone();

    let put_handle = tokio::spawn(async move {
        for count in 1..=100 {
            put_cached.put_with_weight(count, count, 20).unwrap().handle().await;
        }
    });
    put_handle.await.unwrap();

    let delete_cached = cached.clone();
    let delete_handle = tokio::spawn(async move {
        for count in 50..=70 {
            delete_cached.delete(count).unwrap().handle().await;
        }
    });
    delete_handle.await.unwrap();

    let deleted_range = 50..=70;
    for count in 1..=100 {
        if deleted_range.contains(&count) {
            assert_eq!(None, cached.get(&count));
        } else {
            assert_eq!(Some(count), cached.get(&count));
        }
    }
}