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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//! Small structures based around entries in the cache.
//!
//! Each entry has an associated value and optional expiration,
//! and access functions for both. To be more convenient to the
//! called, a `CacheEntry<V>` will also dereference to `V`.
use std::marker::PhantomData;
use std::ops::Range;
use std::ops::{Deref, DerefMut};
use std::time::{Duration, Instant};

use rand::prelude::*;

/// Represents an entry inside the cache.
///
/// Each entry has a value and optional expiration associated, with
/// the value being seen through the `Deref` trait for convenience.
#[derive(Debug)]
pub struct CacheEntry<V> {
    pub(crate) value: V,
    pub(crate) expiration: Option<CacheExpiration>,
}

impl<V> CacheEntry<V> {
    /// Retrieve the expiration associated with a cache entry.
    pub fn expiration(&self) -> Option<&CacheExpiration> {
        self.expiration.as_ref()
    }

    /// Retrieve whether a cache entry has passed expiration.
    pub fn is_expired(&self) -> bool {
        if let Some(expiration) = self.expiration() {
            if expiration.instant() < &Instant::now() {
                return true;
            }
        }
        false
    }

    /// Retrieve a reference to a value in a cache entry.
    pub fn value(&self) -> &V {
        &self.value
    }

    /// Retrieve a mutable reference to a value in a cache entry.
    pub fn value_mut(&mut self) -> &mut V {
        &mut self.value
    }
}

impl<V> Deref for CacheEntry<V> {
    type Target = V;

    // Derefs a cache entry to the internal value.
    fn deref(&self) -> &Self::Target {
        self.value()
    }
}

// Derefs a cache entry to the mutable internal value.
impl<V> DerefMut for CacheEntry<V> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.value_mut()
    }
}

/// Small structure to represent expiration in a cache.
///
/// Expirations are constructed using the `From` and `Into` traits
/// from the standard library; there are no other functions.
///
/// There are currently several supported conversions:
///
/// * `u64` -> a number of milliseconds to pass before an entry should expire.
/// * `Instant` -> an exact time that an entry should expire.
/// * `Duration` -> a duration to pass before an entry should expire.
/// * `Range<u64>` -> a random range of milliseconds to sample from to
///                   determine when an entry should expire.
///
/// Other conversions may be added in future, but this should suffice for most
/// cases. Any of these types may be passed to the insertion methods on a cache
/// type when adding entries to a cache.
#[derive(Debug)]
pub struct CacheExpiration {
    instant: Instant,
}

impl CacheExpiration {
    /// Retrieve the instant associated with this expiration.
    pub fn instant(&self) -> &Instant {
        &self.instant
    }

    /// Retrieve the time remaning before expiration.
    pub fn remaining(&self) -> Duration {
        self.instant.saturating_duration_since(Instant::now())
    }
}

// Automatic conversation from `Instant`.
impl From<Instant> for CacheExpiration {
    fn from(instant: Instant) -> Self {
        Self { instant }
    }
}

// Automatic conversation from `u64`.
impl From<u64> for CacheExpiration {
    fn from(millis: u64) -> Self {
        Duration::from_millis(millis).into()
    }
}

// Automatic conversation from `Duration`.
impl From<Duration> for CacheExpiration {
    fn from(duration: Duration) -> Self {
        Instant::now().checked_add(duration).unwrap().into()
    }
}

// Automatic conversation from `u64`.
impl From<Range<u64>> for CacheExpiration {
    fn from(range: Range<u64>) -> Self {
        rand::thread_rng().gen_range(range).into()
    }
}

/// Read guard for references to the inner cache structure.
///
/// This structure is required to return references to the inner cache entries
/// when using locking mechanisms. This structure should be transparent for the
/// most part as it implements `Deref` to convert itself into the inner value.
#[derive(Debug)]
pub struct CacheEntryReadGuard<'a, V> {
    pub(crate) entry: *const CacheEntry<V>,
    pub(crate) marker: PhantomData<&'a CacheEntry<V>>,
}

impl<'a, V> Deref for CacheEntryReadGuard<'a, V> {
    type Target = V;

    // Derefs a cache guard to the internal entry.
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.entry }
    }
}

// Stores a raw pointer to `T`, so if `T` is `Sync`, the lock guard over `T` is `Send`.
unsafe impl<V> Send for CacheEntryReadGuard<'_, V> where V: Sized + Sync {}
unsafe impl<V> Sync for CacheEntryReadGuard<'_, V> where V: Sized + Send + Sync {}