Skip to content

Commit

Permalink
First version of the library
Browse files Browse the repository at this point in the history
  • Loading branch information
Emulator000 committed Sep 25, 2020
1 parent 8b9dc1f commit fbad62c
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
/target
Cargo.lock
.idea
14 changes: 14 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -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 <[email protected]>"]
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"] }
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -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::<Object, _>("test").await.unwrap().unwrap();

if cached_object.value == 1 {
println!("Hi from Simple Cache!");
}
}
```
129 changes: 129 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -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<dyn Any + Send + Sync>;
type CacheObject = Option<ArcSwap<AnyObject>>;

pub trait CacheItem: Send + Sync {}

pub enum CacheResult {
Ok,
Error,
}

#[derive(Clone)]
pub struct Cache<K> {
items: Arc<RwLock<HashMap<K, CacheObject>>>,
}

impl<K> Cache<K>
where
K: Eq + Hash,
{
pub fn new() -> Self {
Self {
items: Arc::new(RwLock::new(HashMap::new())),
}
}

pub async fn get<T: 'static + CacheItem, Q: ?Sized>(&self, key: &Q) -> Option<Option<Arc<T>>>
where
K: Borrow<Q>,
Q: Hash + Eq,
{
match self.items.read().await.get(key) {
Some(object) => match object {
Some(object) => Some(match object.load().downcast_ref::<Arc<T>>() {
Some(value) => Some(value.to_owned()),
None => None,
}),
None => Some(None),
},
None => None,
}
}

pub async fn insert<T: 'static + CacheItem>(&self, key: K, value: Option<T>) -> 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<Q: ?Sized>(&self, key: &Q) -> CacheResult
where
K: Borrow<Q>,
Q: Hash + Eq,
{
match self.items.write().await.remove(key) {
Some(_) => CacheResult::Ok,
None => CacheResult::Error,
}
}
}

impl<K> Default for Cache<K>
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::<Object, _>("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::<Object, _>("test").await.is_none(), true);
}
}

0 comments on commit fbad62c

Please sign in to comment.