use std::borrow::Cow;
use std::error::Error;
use std::fmt;
use std::time::Duration;
use bytes::Bytes;
use serde::{de::DeserializeOwned, Serialize};
pub type Result<T> = std::result::Result<T, CacheError>;
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CacheKey<'a>(Cow<'a, str>);
impl<'a> CacheKey<'a> {
pub fn new(value: impl Into<Cow<'a, str>>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_owned(self) -> CacheKey<'static> {
CacheKey(Cow::Owned(self.0.into_owned()))
}
}
impl<'a> From<&'a str> for CacheKey<'a> {
fn from(value: &'a str) -> Self {
Self::new(value)
}
}
impl From<String> for CacheKey<'static> {
fn from(value: String) -> Self {
Self::new(Cow::Owned(value))
}
}
impl fmt::Display for CacheKey<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct CacheOptions {
ttl: Option<Duration>,
tags: Vec<String>,
}
impl CacheOptions {
pub fn new() -> Self {
Self::default()
}
pub fn ttl(mut self, ttl: Duration) -> Self {
self.ttl = Some(ttl);
self
}
pub fn tag(mut self, tag: impl Into<String>) -> Self {
self.tags.push(tag.into());
self
}
pub fn tags<I, S>(mut self, tags: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.tags = tags.into_iter().map(Into::into).collect();
self
}
pub fn ttl_value(&self) -> Option<Duration> {
self.ttl
}
pub fn tags_value(&self) -> &[String] {
&self.tags
}
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub loads: u64,
pub single_flight_joins: u64,
pub invalidations: u64,
pub evictions: u64,
}
pub trait CacheCodec: Clone + Send + Sync + 'static {
fn encode<T>(&self, value: &T) -> Result<Bytes>
where
T: Serialize;
fn decode<T>(&self, bytes: &Bytes) -> Result<T>
where
T: DeserializeOwned;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct PostcardCodec;
impl CacheCodec for PostcardCodec {
fn encode<T>(&self, value: &T) -> Result<Bytes>
where
T: Serialize,
{
postcard::to_allocvec(value)
.map(Bytes::from)
.map_err(|source| CacheError::Encode(source.to_string()))
}
fn decode<T>(&self, bytes: &Bytes) -> Result<T>
where
T: DeserializeOwned,
{
postcard::from_bytes(bytes).map_err(|source| CacheError::Decode(source.to_string()))
}
}
#[derive(Debug, Clone, thiserror::Error)]
pub enum CacheError {
#[error("cache encode error: {0}")]
Encode(String),
#[error("cache decode error: {0}")]
Decode(String),
#[error("cache loader error: {0}")]
Loader(String),
#[error("cache backend error: {0}")]
Backend(String),
}
impl CacheError {
pub fn loader<E>(source: E) -> Self
where
E: Error + Send + Sync + 'static,
{
Self::Loader(source.to_string())
}
}