use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
use cachet_tier::DynamicCache;
use tick::Clock;
use super::buildable::{Buildable, type_name};
use super::cache::CacheBuilder;
use super::fallback::FallbackBuilder;
use super::sealed::{CacheTierBuilder, Sealed};
use crate::telemetry::CacheTelemetry;
use crate::transform::TransformAdapter;
use crate::{CacheTier, Codec, Encoder};
pub struct TransformBuilder<K, V, KT, VT, Pre, Post = ()> {
pre: Pre,
post: Post,
key_encoder: Box<dyn Encoder<K, KT>>,
value_codec: Box<dyn Codec<V, VT>>,
clock: Clock,
telemetry: CacheTelemetry,
stampede_protection: bool,
_phantom: PhantomData<(K, V, KT, VT)>,
}
impl<K, V, KT, VT, Pre: Debug, Post: Debug> Debug for TransformBuilder<K, V, KT, VT, Pre, Post> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TransformBuilder")
.field("pre", &self.pre)
.field("post", &self.post)
.field("K", &std::any::type_name::<K>())
.field("KT", &std::any::type_name::<KT>())
.field("V", &std::any::type_name::<V>())
.field("VT", &std::any::type_name::<VT>())
.finish_non_exhaustive()
}
}
impl<K, V, CT> CacheBuilder<K, V, CT>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
CT: CacheTier<K, V> + Send + Sync + 'static,
{
#[must_use]
pub fn transform<KT, VT>(
self,
key_encoder: impl Encoder<K, KT> + 'static,
value_codec: impl Codec<V, VT> + 'static,
) -> TransformBuilder<K, V, KT, VT, Self>
where
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
{
let clock = self.clock.clone();
let telemetry = self.telemetry.clone();
let stampede_protection = self.stampede_protection;
TransformBuilder {
pre: self,
post: (),
key_encoder: Box::new(key_encoder),
value_codec: Box::new(value_codec),
clock,
telemetry,
stampede_protection,
_phantom: PhantomData,
}
}
}
impl<K, V, PB, FB> FallbackBuilder<K, V, PB, FB>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
PB: CacheTierBuilder<K, V>,
FB: CacheTierBuilder<K, V>,
{
#[must_use]
pub fn transform<KT, VT>(
self,
key_encoder: impl Encoder<K, KT> + 'static,
value_codec: impl Codec<V, VT> + 'static,
) -> TransformBuilder<K, V, KT, VT, Self>
where
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
{
let clock = self.clock.clone();
let telemetry = self.telemetry.clone();
let stampede_protection = self.stampede_protection;
TransformBuilder {
pre: self,
post: (),
key_encoder: Box::new(key_encoder),
value_codec: Box::new(value_codec),
clock,
telemetry,
stampede_protection,
_phantom: PhantomData,
}
}
}
impl<K, V, KT, VT, Pre> TransformBuilder<K, V, KT, VT, Pre, ()>
where
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
{
pub fn fallback<FB>(self, fallback: FB) -> TransformBuilder<K, V, KT, VT, Pre, FB>
where
FB: CacheTierBuilder<KT, VT>,
{
TransformBuilder {
pre: self.pre,
post: fallback,
key_encoder: self.key_encoder,
value_codec: self.value_codec,
clock: self.clock,
telemetry: self.telemetry,
stampede_protection: self.stampede_protection,
_phantom: PhantomData,
}
}
}
impl<K, V, KT, VT, Pre, Post> TransformBuilder<K, V, KT, VT, Pre, Post>
where
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
Post: CacheTierBuilder<KT, VT>,
{
pub fn fallback<FB>(self, fallback: FB) -> TransformBuilder<K, V, KT, VT, Pre, FallbackBuilder<KT, VT, Post, FB>>
where
FB: CacheTierBuilder<KT, VT>,
{
let clock = self.clock.clone();
let telemetry = self.telemetry.clone();
let stampede_protection = self.stampede_protection;
let post_chain = FallbackBuilder {
name: None,
primary_builder: self.post,
fallback_builder: fallback,
clock: clock.clone(),
refresh: None,
telemetry: telemetry.clone(),
stampede_protection,
_phantom: PhantomData,
};
TransformBuilder {
pre: self.pre,
post: post_chain,
key_encoder: self.key_encoder,
value_codec: self.value_codec,
clock,
telemetry,
stampede_protection,
_phantom: PhantomData,
}
}
}
impl<K, V, KT, VT, Pre, Post> Sealed for TransformBuilder<K, V, KT, VT, Pre, Post>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
{
}
impl<K, V, KT, VT, Pre, Post> CacheTierBuilder<K, V> for TransformBuilder<K, V, KT, VT, Pre, Post>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
{
}
#[expect(private_bounds, reason = "Buildable is an internal trait")]
impl<K, V, KT, VT, Pre, Post> TransformBuilder<K, V, KT, VT, Pre, Post>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
Pre: Buildable<K, V>,
Post: Buildable<KT, VT>,
{
pub fn build(self) -> crate::Cache<K, V> {
<Self as Buildable<K, V>>::build(self)
}
}
impl<K, V, KT, VT, Pre, Post> Buildable<K, V> for TransformBuilder<K, V, KT, VT, Pre, Post>
where
K: Clone + Hash + Eq + Send + Sync + 'static,
V: Clone + Send + Sync + 'static,
KT: Clone + Hash + Eq + Send + Sync + 'static,
VT: Clone + Send + Sync + 'static,
Pre: Buildable<K, V>,
Post: Buildable<KT, VT>,
{
type TierOutput = DynamicCache<K, V>;
fn build(self) -> crate::Cache<K, V> {
let clock = self.clock.clone();
let telemetry = self.telemetry.clone();
let stampede_protection = self.stampede_protection;
let tier = self.build_tier(clock.clone(), telemetry);
crate::Cache::new(type_name::<Self::TierOutput>(None), tier, clock, stampede_protection)
}
fn build_tier(self, clock: Clock, telemetry: CacheTelemetry) -> Self::TierOutput {
let pre_tier = self.pre.build_tier(clock.clone(), telemetry.clone());
let post_tier = self.post.build_tier(clock.clone(), telemetry.clone());
let adapted = TransformAdapter::from_boxed(post_tier, self.key_encoder, self.value_codec);
let fallback = crate::fallback::FallbackCache::new(type_name::<Self::TierOutput>(None), pre_tier, adapted, clock, None, telemetry);
DynamicCache::new(fallback)
}
}