use crate::ttl::Time;
use parking_lot::{MappedRwLockReadGuard, MappedRwLockWriteGuard};
use std::{
fmt::{Debug, Display, Formatter},
time::Duration,
};
pub struct ValueRef<'a, V> {
guard: MappedRwLockReadGuard<'a, V>,
expiration: Time,
}
impl<'a, V> ValueRef<'a, V> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn new(guard: MappedRwLockReadGuard<'a, V>, expiration: Time) -> Self {
Self { guard, expiration }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn value(&self) -> &V {
&self.guard
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn release(self) {
drop(self)
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn ttl(&self) -> Duration {
self.expiration.get_ttl()
}
}
impl<V: Copy> ValueRef<'_, V> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn read(self) -> V {
let v = *self.value();
drop(self);
v
}
}
impl<V> AsRef<V> for ValueRef<'_, V> {
fn as_ref(&self) -> &V {
self.value()
}
}
impl<V: Debug> Debug for ValueRef<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ValueRef")
.field("value", self.value())
.field("expiration", &self.expiration)
.finish()
}
}
impl<V: Display> Display for ValueRef<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.value())
}
}
pub struct ValueRefMut<'a, V> {
guard: MappedRwLockWriteGuard<'a, V>,
}
impl<'a, V> ValueRefMut<'a, V> {
#[cfg_attr(not(tarpaulin), inline(always))]
pub(crate) fn new(guard: MappedRwLockWriteGuard<'a, V>) -> Self {
Self { guard }
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn value(&self) -> &V {
&self.guard
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn value_mut(&mut self) -> &mut V {
&mut self.guard
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn write(&mut self, val: V) {
*self.guard = val
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn write_once(mut self, val: V) {
*self.guard = val;
self.release();
}
#[cfg_attr(not(tarpaulin), inline(always))]
pub fn release(self) {
drop(self)
}
}
impl<V: Clone> ValueRefMut<'_, V> {
pub fn clone_inner(&self) -> V {
(*self.guard).clone()
}
}
impl<V: Copy> ValueRefMut<'_, V> {
pub fn read(self) -> V {
let v = *self.guard;
drop(self);
v
}
}
impl<V: Debug> Debug for ValueRefMut<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", &*self.guard)
}
}
impl<V: Display> Display for ValueRefMut<'_, V> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &*self.guard)
}
}
impl<V> AsRef<V> for ValueRefMut<'_, V> {
fn as_ref(&self) -> &V {
self.value()
}
}
impl<V> AsMut<V> for ValueRefMut<'_, V> {
fn as_mut(&mut self) -> &mut V {
self.value_mut()
}
}
pub(crate) fn vec_to_array<T, const N: usize>(v: Vec<T>) -> [T; N] {
v.try_into()
.unwrap_or_else(|v: Vec<T>| panic!("Expected a Vec of length {} but it was {}", N, v.len()))
}
#[cfg(test)]
mod test {
use crate::{ValueRef, ValueRefMut, store::StoreItem, ttl::Time};
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::collections::HashMap;
#[test]
fn test_value_ref() {
let mut m = HashMap::new();
m.insert(
1,
StoreItem {
key: 1,
conflict: 0,
version: 0,
generation: 0,
value: 3,
expiration: Time::now(),
},
);
m.insert(
2,
StoreItem {
key: 2,
conflict: 0,
version: 0,
generation: 0,
value: 3,
expiration: Time::now(),
},
);
let lm = RwLock::new(m);
let l = lm.read();
let expiration = l.get(&1).unwrap().expiration;
let mapped = RwLockReadGuard::map(l, |m| &m.get(&1).unwrap().value);
let vr = ValueRef::new(mapped, expiration);
assert_eq!(vr.as_ref(), &3);
eprintln!("{}", vr);
eprintln!("{:?}", vr);
}
#[test]
fn test_value_ref_mut() {
let mut m = HashMap::new();
m.insert(
1,
StoreItem {
key: 1,
conflict: 0,
version: 0,
generation: 0,
value: 3,
expiration: Time::now(),
},
);
m.insert(
2,
StoreItem {
key: 2,
conflict: 0,
version: 0,
generation: 0,
value: 3,
expiration: Time::now(),
},
);
let lm = RwLock::new(m);
let l = lm.write();
let mapped = RwLockWriteGuard::map(l, |m| &mut m.get_mut(&1).unwrap().value);
let mut vr = ValueRefMut::new(mapped);
assert_eq!(vr.as_ref(), &3);
assert_eq!(vr.as_mut(), &mut 3);
assert_eq!(vr.value(), &3);
assert_eq!(vr.clone_inner(), 3);
eprintln!("{}", vr);
eprintln!("{:?}", vr);
vr.write_once(4);
}
}