1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
extern crate r2d2;
extern crate redis;
extern crate dns_lookup;

mod error;
mod memory_cache;
mod redis_cache;

use std::{any::Any, collections::HashMap};

use memory_cache::MemoryCache;
use redis_cache::RedisCache;
pub use error::CacheError;

pub type Result<T> = std::result::Result<T, CacheError>;

pub trait Cacheable {
    fn model_name() -> &'static str where Self: Sized;
    fn to_redis_obj(&self) -> Vec<(String, String)>;
    fn from_redis_obj(obj: HashMap<String, String>) -> Result<Self> where Self: Sized;
    fn expires_after(&self) -> Option<usize>;
    fn as_any(&self) -> &Any;
}

#[cfg(feature = "hashset")]
trait HashSetAccess {
    fn set_insert<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<()>;
    fn set_contains<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<bool>;
    fn set_remove<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<()>;
}

trait CacheAccess {
    fn insert<K: ToString, O: Cacheable + Clone + 'static>(&self, key: K, obj: O) -> Result<()>;
    fn get<K: ToString, O: Cacheable + Clone + 'static>(&self, key: K) -> Result<Option<O>>;
    fn contains_key<K: ToString, O: Cacheable + Clone + 'static>(&self, key: K) -> Result<bool>;
    fn remove<K: ToString, O: Cacheable>(&self, key: K) -> Result<()>;
}

pub enum Cache {
    Memory(MemoryCache),
    Redis(RedisCache),
}

impl Clone for Cache {
    fn clone(&self) -> Self {
        match *self {
            Memory(ref c) => Memory(c.clone()),
            Redis(ref c) => Redis(c.clone()),
        }
    }
}

use Cache::*;

impl Cache {
    pub fn insert<K: ToString, O: Cacheable + Clone + 'static>(&self, key: K, obj: O) -> Result<()> {
        match *self {
            Memory(ref c) => c.insert(key, obj),
            Redis(ref c) => c.insert(key, obj),
        }
    }

    pub fn get<K: ToString, O: Cacheable + Clone + 'static>(&self, key: K) -> Result<Option<O>> {
        match *self {
            Memory(ref c) => c.get::<K, O>(key),
            Redis(ref c) => c.get::<K, O>(key),
        }
    }

    pub fn remove<K: ToString, O: Cacheable>(&self, key: K) -> Result<()> {
        match *self {
            Memory(ref c) => c.remove::<K, O>(key),
            Redis(ref c) => c.remove::<K, O>(key),
        }
    }

    #[cfg(feature = "hashset")]
    pub fn set_insert<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<()> {
        match *self {
            Memory(ref c) => c.set_insert(group_id, member),
            Redis(ref c) => c.set_insert(group_id, member),
        }
    }

    #[cfg(feature = "hashset")]
    pub fn set_contains<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<bool> {
        match *self {
            Memory(ref c) => c.set_contains(group_id, member),
            Redis(ref c) => c.set_contains(group_id, member),
        }
    }

    #[cfg(feature = "hashset")]
    pub fn set_remove<G: ToString, K: ToString>(&self, group_id: G, member: K) -> Result<()> {
        match *self {
            Memory(ref c) => c.set_remove(group_id, member),
            Redis(ref c) => c.set_remove(group_id, member),
        }
    }
}

unsafe impl Send for Cache {}
unsafe impl Sync for Cache {}

pub fn memory() -> Cache {
    Memory(MemoryCache::new())
}

pub fn redis(host: &str, password: Option<&str>, db: Option<u16>) -> Result<Cache> {
    match RedisCache::new(host, password, db) {
        Ok(rc) => Ok(Redis(rc)),
        Err(e) => Err(e),
    }
}