use serde::{Deserialize, Serialize};
pub const DEFAULT_MAX_RETAINED_TAIL_TOKENS: usize = 20_000;
pub const DEFAULT_SUMMARY_MAX_TOKENS: usize = 4_096;
const fn default_max_retained_tail_tokens() -> usize {
DEFAULT_MAX_RETAINED_TAIL_TOKENS
}
const fn default_summary_max_tokens() -> usize {
DEFAULT_SUMMARY_MAX_TOKENS
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct CompactionConfig {
pub threshold_tokens: usize,
pub retain_recent: usize,
pub min_messages_for_compaction: usize,
pub auto_compact: bool,
#[serde(default = "default_max_retained_tail_tokens")]
pub max_retained_tail_tokens: usize,
#[serde(default = "default_summary_max_tokens")]
pub summary_max_tokens: usize,
}
impl Default for CompactionConfig {
fn default() -> Self {
Self {
threshold_tokens: 80_000,
retain_recent: 10,
min_messages_for_compaction: 20,
auto_compact: true,
max_retained_tail_tokens: DEFAULT_MAX_RETAINED_TAIL_TOKENS,
summary_max_tokens: DEFAULT_SUMMARY_MAX_TOKENS,
}
}
}
impl CompactionConfig {
#[must_use]
pub fn new() -> Self {
Self::default()
}
#[must_use]
pub const fn with_threshold_tokens(mut self, threshold: usize) -> Self {
self.threshold_tokens = threshold;
self
}
#[must_use]
pub const fn with_retain_recent(mut self, count: usize) -> Self {
self.retain_recent = count;
self
}
#[must_use]
pub const fn with_min_messages(mut self, count: usize) -> Self {
self.min_messages_for_compaction = count;
self
}
#[must_use]
pub const fn with_auto_compact(mut self, auto: bool) -> Self {
self.auto_compact = auto;
self
}
#[must_use]
pub const fn with_max_retained_tail_tokens(mut self, tokens: usize) -> Self {
self.max_retained_tail_tokens = tokens;
self
}
#[must_use]
pub const fn with_summary_max_tokens(mut self, tokens: usize) -> Self {
self.summary_max_tokens = tokens;
self
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let config = CompactionConfig::default();
assert_eq!(config.threshold_tokens, 80_000);
assert_eq!(config.retain_recent, 10);
assert_eq!(config.min_messages_for_compaction, 20);
assert!(config.auto_compact);
assert_eq!(
config.max_retained_tail_tokens,
DEFAULT_MAX_RETAINED_TAIL_TOKENS
);
assert_eq!(config.summary_max_tokens, DEFAULT_SUMMARY_MAX_TOKENS);
}
#[test]
fn test_builder_pattern() {
let config = CompactionConfig::new()
.with_threshold_tokens(50_000)
.with_retain_recent(5)
.with_min_messages(10)
.with_auto_compact(false)
.with_max_retained_tail_tokens(40_000)
.with_summary_max_tokens(8_000);
assert_eq!(config.threshold_tokens, 50_000);
assert_eq!(config.retain_recent, 5);
assert_eq!(config.min_messages_for_compaction, 10);
assert!(!config.auto_compact);
assert_eq!(config.max_retained_tail_tokens, 40_000);
assert_eq!(config.summary_max_tokens, 8_000);
}
#[test]
fn test_deserialize_without_new_fields_uses_defaults() -> anyhow::Result<()> {
let json = r#"{
"threshold_tokens": 1234,
"retain_recent": 7,
"min_messages_for_compaction": 3,
"auto_compact": true
}"#;
let config: CompactionConfig = serde_json::from_str(json)?;
assert_eq!(config.threshold_tokens, 1234);
assert_eq!(config.retain_recent, 7);
assert_eq!(
config.max_retained_tail_tokens,
DEFAULT_MAX_RETAINED_TAIL_TOKENS
);
assert_eq!(config.summary_max_tokens, DEFAULT_SUMMARY_MAX_TOKENS);
Ok(())
}
}