From fbad62cf9e3688b7d7215ebbff6669c5bed4f572 Mon Sep 17 00:00:00 2001 From: Emulator000 Date: Fri, 25 Sep 2020 18:31:13 +0200 Subject: [PATCH] First version of the library --- .gitignore | 3 ++ Cargo.toml | 14 ++++++ README.md | 23 ++++++++++ src/lib.rs | 129 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 README.md create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b471067 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +.idea diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..f350b13 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,14 @@ +[package] + name = "simple-cache" + description = "A basic and simple Rust library async/await ready caching implementation for structures." + version = "0.1.0" + authors = ["Emulator000 "] + edition = "2018" + readme = "README.md" + repository = "https://github.com/Emulator000/simple-cache" + license = "MIT" + +[dependencies] + async-std = "^1.6" + arc-swap = "^0.4" + tokio = { version = "^0.2", features = ["full"] } diff --git a/README.md b/README.md new file mode 100644 index 0000000..8bcf22f --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# Simple Cache +A basic and simple Rust library async/await ready caching implementation for structures. + +## Usage +```rust +use simple_cache::Cache; + +fn main() { + let cache = Cache::new(); + let object = Object { + value: 1, + string: String::from("test!"), + }; + + cache.insert("test", Some(object)).await; + + let cached_object = cache.get::("test").await.unwrap().unwrap(); + + if cached_object.value == 1 { + println!("Hi from Simple Cache!"); + } +} +``` diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..8dbc317 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,129 @@ +use std::any::Any; +use std::borrow::Borrow; +use std::collections::HashMap; +use std::hash::Hash; +use std::sync::Arc; + +use async_std::sync::RwLock; + +use arc_swap::ArcSwap; + +type AnyObject = Box; +type CacheObject = Option>; + +pub trait CacheItem: Send + Sync {} + +pub enum CacheResult { + Ok, + Error, +} + +#[derive(Clone)] +pub struct Cache { + items: Arc>>, +} + +impl Cache +where + K: Eq + Hash, +{ + pub fn new() -> Self { + Self { + items: Arc::new(RwLock::new(HashMap::new())), + } + } + + pub async fn get(&self, key: &Q) -> Option>> + where + K: Borrow, + Q: Hash + Eq, + { + match self.items.read().await.get(key) { + Some(object) => match object { + Some(object) => Some(match object.load().downcast_ref::>() { + Some(value) => Some(value.to_owned()), + None => None, + }), + None => Some(None), + }, + None => None, + } + } + + pub async fn insert(&self, key: K, value: Option) -> CacheResult { + match self.items.write().await.insert( + key, + match value { + Some(value) => Some(ArcSwap::new(Arc::new( + Box::new(Arc::new(value)) as AnyObject + ))), + None => None, + }, + ) { + Some(_) => CacheResult::Ok, + None => CacheResult::Error, + } + } + + pub async fn remove(&self, key: &Q) -> CacheResult + where + K: Borrow, + Q: Hash + Eq, + { + match self.items.write().await.remove(key) { + Some(_) => CacheResult::Ok, + None => CacheResult::Error, + } + } +} + +impl Default for Cache +where + K: Eq + Hash, +{ + fn default() -> Self { + Cache::new() + } +} + +#[cfg(test)] +mod tests { + use crate::{Cache, CacheItem}; + + struct Object { + value: i32, + string: String, + } + + impl CacheItem for Object {} + + #[tokio::test] + async fn insert_and_get() { + let cache = Cache::new(); + let object = Object { + value: 1, + string: String::from("test!"), + }; + + cache.insert("test", Some(object)).await; + + let cached_object = cache.get::("test").await.unwrap().unwrap(); + + assert_eq!(cached_object.value, 1); + assert_eq!(cached_object.string, "test!"); + } + + #[tokio::test] + async fn remove() { + let cache = Cache::new(); + let object = Object { + value: 1, + string: String::from("test!"), + }; + + cache.insert("test", Some(object)).await; + cache.remove("test").await; + + assert_eq!(cache.get::("test").await.is_none(), true); + } +}