pub trait Summarizer<T, S = T> {
fn summarize(&self, items: &[&T]) -> S;
}
#[derive(Debug, Clone, Default)]
pub struct ConcatSummarizer {
pub separator: String,
pub max_len: Option<usize>,
}
impl ConcatSummarizer {
pub fn new() -> Self {
Self {
separator: " | ".to_string(),
max_len: None,
}
}
pub fn with_separator(mut self, sep: impl Into<String>) -> Self {
self.separator = sep.into();
self
}
pub fn with_max_len(mut self, len: usize) -> Self {
self.max_len = Some(len);
self
}
}
impl Summarizer<String> for ConcatSummarizer {
fn summarize(&self, items: &[&String]) -> String {
let joined = items
.iter()
.map(|s| s.as_str())
.collect::<Vec<_>>()
.join(&self.separator);
match self.max_len {
Some(max) if joined.len() > max => {
let mut truncated = joined[..max.saturating_sub(3)].to_string();
truncated.push_str("...");
truncated
}
_ => joined,
}
}
}
#[derive(Clone)]
pub struct FnSummarizer<F> {
f: F,
}
impl<F> FnSummarizer<F> {
pub fn new(f: F) -> Self {
Self { f }
}
}
impl<T, S, F> Summarizer<T, S> for FnSummarizer<F>
where
F: Fn(&[&T]) -> S,
{
fn summarize(&self, items: &[&T]) -> S {
(self.f)(items)
}
}
pub fn from_fn<T, S, F>(f: F) -> FnSummarizer<F>
where
F: Fn(&[&T]) -> S,
{
FnSummarizer::new(f)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_concat_summarizer() {
let summarizer = ConcatSummarizer::new().with_separator(", ");
let items = ["a".to_string(), "b".to_string(), "c".to_string()];
let refs: Vec<&String> = items.iter().collect();
let summary = summarizer.summarize(&refs);
assert_eq!(summary, "a, b, c");
}
#[test]
fn test_fn_summarizer() {
let summarizer = from_fn(|items: &[&i32]| items.iter().copied().sum::<i32>());
let items = [1, 2, 3];
let refs: Vec<&i32> = items.iter().collect();
let summary: i32 = summarizer.summarize(&refs);
assert_eq!(summary, 6);
}
}