use tokio::time::Instant;
use crate::prelude::*;
#[derive(Clone)]
pub enum Value {
Ok, Pong, Nil,
Simple(Arc<str>),
Error(Arc<str>),
Integer(i64),
String(Arc<str>),
Multi(Arc<[Self]>),
Expire((Arc<Self>, Instant)),
Map(HashMap<Self, Self>),
Set(HashSet<Self>),
Push(Arc<[Self]>), }
impl PartialEq for Value {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Ok, Self::Ok) | (Self::Pong, Self::Pong) | (Self::Nil, Self::Nil) => true,
(Self::Simple(a), Self::Simple(b))
| (Self::Error(a), Self::Error(b))
| (Self::String(a), Self::String(b)) => a == b,
(Self::Integer(a), Self::Integer(b)) => a == b,
(Self::Multi(a), Self::Multi(b)) | (Self::Push(a), Self::Push(b)) => a == b,
(Self::Map(a), Self::Map(b)) => a == b,
(Self::Set(a), Self::Set(b)) => a == b,
(Self::Expire(_), Self::Expire(_)) => {
unreachable!("Expire values should not be compared")
}
_ => false,
}
}
}
impl Eq for Value {}
impl std::hash::Hash for Value {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
Self::Ok => "ok".hash(state),
Self::Nil => "nil".hash(state),
Self::Pong => "pong".hash(state),
Self::Simple(s) | Self::Error(s) | Self::String(s) => s.hash(state),
Self::Integer(i) => i.hash(state),
Self::Multi(v) | Self::Push(v) => v.hash(state),
Self::Expire((v, _)) => v.hash(state),
Self::Map(_) | Self::Set(_) => unreachable!("Map and Set should not be hashed"),
}
}
}
#[macro_export]
macro_rules! value_error {
($($arg:tt)*) => {
$crate::value::Value::Error(format!($($arg)*).into())
};
}
#[macro_export]
macro_rules! value_multi {
() => {
$crate::value::statics::EMPTY_MULTI.clone()
};
($($arg:tt)*) => {
$crate::value::Value::Multi(vec![$($arg)*].into())
};
}
#[macro_export]
macro_rules! value_push {
($($arg:tt)*) => {
$crate::value::Value::Push(vec![$($arg)*].into())
};
}
#[macro_export]
macro_rules! value_map {
() => {
$crate::value::statics::EMPTY_MAP.clone()
};
($($key:expr => $value:expr),* $(,)?) => {
$crate::value::Value::Map(
vec![$(($key.into(), $value.into())),*].into_iter().collect()
)
};
}
impl Value {
#[must_use]
pub fn expired(&self) -> bool {
match self {
Self::Expire((_, expires_at)) => Instant::now() > *expires_at,
_ => false,
}
}
pub fn set_expire(&mut self, expires_at: Instant) {
match self {
Self::Expire((_, e)) => *e = expires_at,
_ => *self = Self::Expire((Arc::new(self.clone()), expires_at)),
}
}
#[must_use]
pub fn is_some(&self) -> bool {
match self {
Self::Nil => false,
Self::Expire((_, expires_at)) => Instant::now() <= *expires_at,
_ => true,
}
}
#[must_use]
pub fn inner(&self) -> &Self {
match self {
Self::Expire((v, _)) => v.inner(),
_ => self,
}
}
#[must_use]
pub fn inner_mut(&mut self) -> Option<&mut Self> {
match self {
Self::Expire((v, _)) => Arc::get_mut(v),
_ => Some(self),
}
}
#[must_use]
pub const fn expire_at(&self) -> Option<Instant> {
match self {
Self::Expire((_, expires_at)) => Some(*expires_at),
_ => None,
}
}
#[must_use]
pub fn as_i64(&self) -> Option<i64> {
match self.inner() {
Self::Integer(i) => Some(*i),
Self::String(s) => s.parse::<i64>().ok(),
_ => None,
}
}
#[must_use]
pub fn as_string(&self) -> Option<Arc<str>> {
match self.inner() {
Self::String(s) => Some(s.clone()),
Self::Integer(i) => Some(i.to_string().into()),
_ => None,
}
}
#[must_use]
pub fn is_none(&self) -> bool {
!self.is_some()
}
#[must_use]
pub fn is_primitive(&self) -> bool {
matches!(
self.inner(),
Self::Simple(_) | Self::Error(_) | Self::Integer(_) | Self::String(_)
)
}
}
impl From<Option<Self>> for Value {
fn from(value: Option<Self>) -> Self {
value.unwrap_or(Self::Nil)
}
}
impl From<String> for Value {
fn from(value: String) -> Self {
Self::String(value.into())
}
}
impl From<&str> for Value {
fn from(value: &str) -> Self {
Self::String(value.into())
}
}
impl From<Arc<str>> for Value {
fn from(value: Arc<str>) -> Self {
Self::String(value)
}
}
impl From<Vec<Self>> for Value {
fn from(value: Vec<Self>) -> Self {
Self::Multi(value.into())
}
}
impl From<&[Self]> for Value {
fn from(value: &[Self]) -> Self {
Self::Multi(value.into())
}
}
impl From<i64> for Value {
fn from(value: i64) -> Self {
Self::Integer(value)
}
}
impl From<Option<Arc<str>>> for Value {
fn from(value: Option<Arc<str>>) -> Self {
value.map_or(Self::Nil, Self::String)
}
}
impl std::fmt::Debug for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Ok => write!(f, "OK"),
Self::Pong => write!(f, "PONG"),
Self::Nil => write!(f, "(nil)"),
Self::Simple(s) | Self::String(s) | Self::Error(s) => write!(f, "\"{s}\""),
Self::Integer(i) => write!(f, "{i}"),
Self::Multi(v) => write!(f, "{v:?}"),
Self::Expire((v, expires_at)) => {
write!(f, "EXPIRE(value={v:?}, expires_at={expires_at:?})")
}
Self::Map(m) => write!(f, "%{m:?}"),
Self::Set(s) => write!(f, "~{s:?}"),
Self::Push(p) => write!(f, ">{p:?}"),
}
}
}
pub mod statics {
use std::collections::HashMap;
use std::sync::{Arc, LazyLock};
use super::Value;
static EMPTY_ARC: LazyLock<Arc<[Value]>> = LazyLock::new(|| Arc::from([]));
pub static EMPTY_MULTI: LazyLock<Value> = LazyLock::new(|| Value::Multi(EMPTY_ARC.clone()));
pub static EMPTY_MAP: LazyLock<Value> = LazyLock::new(|| Value::Map(HashMap::default()));
}