#[derive(Debug, Clone)]
pub(crate) struct Examples<T> {
kept: Vec<T>,
total: usize,
cap: usize,
}
#[cfg_attr(not(feature = "decode"), allow(dead_code))]
impl<T> Examples<T> {
pub fn new(cap: usize) -> Self {
Examples {
kept: Vec::new(),
total: 0,
cap,
}
}
pub fn collect(cap: usize, iter: impl IntoIterator<Item = T>) -> Self {
let mut ex = Examples::new(cap);
for item in iter {
ex.push(item);
}
ex
}
pub fn push(&mut self, item: T) {
self.total += 1;
if self.kept.len() < self.cap {
self.kept.push(item);
}
}
pub fn push_with(&mut self, make: impl FnOnce() -> T) {
self.total += 1;
if self.kept.len() < self.cap {
self.kept.push(make());
}
}
pub fn total(&self) -> usize {
self.total
}
pub fn dropped(&self) -> usize {
self.total - self.kept.len()
}
pub fn as_slice(&self) -> &[T] {
&self.kept
}
pub fn into_vec(self) -> Vec<T> {
self.kept
}
pub fn more(&self, tail: &str) -> Option<String> {
(self.dropped() > 0).then(|| format!("… and {} {tail}", self.dropped()))
}
}
impl Examples<String> {
pub fn into_lines(self, tail: &str) -> Vec<String> {
let more = self.more(tail);
let mut lines = self.into_vec();
lines.extend(more);
lines
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_total_counts_everything_offered() {
let mut ex = Examples::new(3);
for i in 0..10 {
ex.push(format!("k{i}"));
}
assert_eq!(ex.as_slice().len(), 3);
assert_eq!(ex.total(), 10);
assert_eq!(ex.dropped(), 7);
assert_eq!(ex.as_slice()[0], "k0", "the first offered are the kept");
assert_eq!(
ex.more("more key(s) with the same finding").as_deref(),
Some("… and 7 more key(s) with the same finding")
);
}
#[test]
fn an_uncapped_run_says_nothing_extra() {
let ex = Examples::collect(20, (0..3).map(|i| format!("k{i}")));
assert_eq!(ex.total(), 3);
assert_eq!(ex.dropped(), 0);
assert_eq!(ex.more("more"), None);
assert_eq!(ex.into_lines("more").len(), 3);
}
#[test]
fn push_with_counts_the_call_not_the_closure() {
let mut built = 0;
let mut ex = Examples::new(2);
for _ in 0..5 {
ex.push_with(|| {
built += 1;
String::from("x")
});
}
assert_eq!(built, 2, "only the kept were built");
assert_eq!(ex.total(), 5, "all five were counted");
assert_eq!(ex.into_lines("more")[2], "… and 3 more");
}
}