use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
use std::sync::{Arc, Condvar, Mutex};
use std::time::Instant;
use ordered_float::OrderedFloat;
use crate::codec::Bytes;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ValueType {
String,
Hash,
Set,
List,
Deque,
ZSet,
}
impl ValueType {
#[must_use]
pub fn as_str(self) -> &'static str {
match self {
ValueType::String => "string",
ValueType::Hash => "hash",
ValueType::Set => "set",
ValueType::List => "list",
ValueType::Deque => "deque",
ValueType::ZSet => "zset",
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Meta {
pub value_type: ValueType,
pub expire_at: Option<Instant>,
}
impl Meta {
#[must_use]
pub fn new(value_type: ValueType) -> Self {
Self {
value_type,
expire_at: None,
}
}
}
#[derive(Debug, Clone)]
pub struct StringEntry {
pub meta: Meta,
pub bytes: Bytes,
}
#[derive(Debug, Clone)]
pub struct HashEntry {
pub meta: Meta,
pub map: HashMap<Bytes, Bytes>,
}
#[derive(Debug, Clone)]
pub struct SetEntry {
pub meta: Meta,
pub set: HashSet<Bytes>,
}
#[derive(Debug)]
pub struct ListInner {
pub deque: VecDeque<Bytes>,
}
#[derive(Debug, Clone)]
pub struct ListEntry {
pub meta: Meta,
pub inner: Arc<(Mutex<ListInner>, Condvar)>,
}
#[derive(Debug, Clone)]
pub struct DequeEntry {
pub meta: Meta,
pub deque: VecDeque<Bytes>,
}
#[derive(Debug, Clone)]
pub struct ZSetEntry {
pub meta: Meta,
pub member_to_score: HashMap<Bytes, f64>,
pub score_to_members: BTreeMap<OrderedFloat<f64>, BTreeSet<Bytes>>,
}
#[derive(Debug, Clone)]
pub enum Entry {
String(StringEntry),
Hash(HashEntry),
Set(SetEntry),
List(ListEntry),
Deque(DequeEntry),
ZSet(ZSetEntry),
}
impl Entry {
#[must_use]
pub fn value_type(&self) -> ValueType {
match self {
Entry::String(_) => ValueType::String,
Entry::Hash(_) => ValueType::Hash,
Entry::Set(_) => ValueType::Set,
Entry::List(_) => ValueType::List,
Entry::Deque(_) => ValueType::Deque,
Entry::ZSet(_) => ValueType::ZSet,
}
}
#[must_use]
pub fn meta(&self) -> &Meta {
match self {
Entry::String(e) => &e.meta,
Entry::Hash(e) => &e.meta,
Entry::Set(e) => &e.meta,
Entry::List(e) => &e.meta,
Entry::Deque(e) => &e.meta,
Entry::ZSet(e) => &e.meta,
}
}
pub fn meta_mut(&mut self) -> &mut Meta {
match self {
Entry::String(e) => &mut e.meta,
Entry::Hash(e) => &mut e.meta,
Entry::Set(e) => &mut e.meta,
Entry::List(e) => &mut e.meta,
Entry::Deque(e) => &mut e.meta,
Entry::ZSet(e) => &mut e.meta,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
fn b(s: &str) -> Bytes {
Arc::from(s.as_bytes())
}
#[test]
fn test_meta() {
let meta = Meta::new(ValueType::String);
assert_eq!(meta.value_type, ValueType::String);
assert_eq!(meta.expire_at, None);
let meta_with_expiry = Meta {
value_type: ValueType::Hash,
expire_at: Some(Instant::now() + Duration::from_secs(10)),
};
assert_eq!(meta_with_expiry.value_type, ValueType::Hash);
assert!(meta_with_expiry.expire_at.is_some());
}
#[test]
fn test_string_entry() {
let bytes: Bytes = Arc::from(vec![1, 2, 3]);
let e = StringEntry {
meta: Meta::new(ValueType::String),
bytes: bytes.clone(),
};
assert_eq!(e.meta.value_type, ValueType::String);
assert_eq!(&*e.bytes, &*bytes);
}
#[test]
fn test_hash_entry() {
let map = HashMap::from([(b("key"), b("value"))]);
let e = HashEntry {
meta: Meta::new(ValueType::Hash),
map: map.clone(),
};
assert_eq!(e.meta.value_type, ValueType::Hash);
assert_eq!(e.map, map);
}
#[test]
fn test_set_entry() {
let set = HashSet::from([b("member")]);
let e = SetEntry {
meta: Meta::new(ValueType::Set),
set: set.clone(),
};
assert_eq!(e.meta.value_type, ValueType::Set);
assert_eq!(e.set, set);
}
#[test]
fn test_list_entry() {
let inner = Arc::new((
Mutex::new(ListInner {
deque: VecDeque::new(),
}),
Condvar::new(),
));
let e = ListEntry {
meta: Meta::new(ValueType::List),
inner: inner.clone(),
};
assert_eq!(e.meta.value_type, ValueType::List);
assert!(Arc::ptr_eq(&e.inner, &inner));
}
#[test]
fn test_deque_entry() {
let deque = VecDeque::from(vec![b("item1"), b("item2")]);
let e = DequeEntry {
meta: Meta::new(ValueType::Deque),
deque: deque.clone(),
};
assert_eq!(e.meta.value_type, ValueType::Deque);
assert_eq!(e.deque, deque);
}
#[test]
fn test_zset_entry() {
let member_to_score = HashMap::from([(b("member"), 1.0)]);
let score_to_members = BTreeMap::from([(OrderedFloat(1.0), BTreeSet::from([b("member")]))]);
let e = ZSetEntry {
meta: Meta::new(ValueType::ZSet),
member_to_score: member_to_score.clone(),
score_to_members: score_to_members.clone(),
};
assert_eq!(e.meta.value_type, ValueType::ZSet);
assert_eq!(e.member_to_score, member_to_score);
assert_eq!(e.score_to_members, score_to_members);
}
}