#[cfg(not(feature = "std"))]
use crate::nostd_prelude::*;
use super::{StreamData, StreamId};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct PendingSummary {
pub total: u64,
pub id_range: Option<(StreamId, StreamId)>,
pub by_consumer: Vec<(Vec<u8>, u64)>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct PendingExtended {
pub rows: Vec<PendingExtendedRow>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[non_exhaustive]
pub struct PendingExtendedRow {
pub id: StreamId,
pub consumer: Vec<u8>,
pub idle_ms: u64,
pub delivery_count: u64,
}
impl StreamData {
pub fn pending_summary(&self, group: &[u8]) -> Option<PendingSummary> {
let g = self.groups.get(group)?;
let total = g.pel.len() as u64;
let id_range = match (g.pel.keys().next(), g.pel.keys().next_back()) {
(Some(lo), Some(hi)) => Some((*lo, *hi)),
_ => None,
};
let mut counts: Vec<(Vec<u8>, u64)> = Vec::new();
for p in g.pel.values() {
if let Some((_, n)) = counts.iter_mut().find(|(name, _)| name == p.consumer.as_slice())
{
*n += 1;
} else {
counts.push((p.consumer.to_vec(), 1));
}
}
counts.sort_unstable_by(|a, b| a.0.cmp(&b.0));
Some(PendingSummary { total, id_range, by_consumer: counts })
}
#[allow(clippy::too_many_arguments)]
pub fn pending_extended(
&self,
group: &[u8],
idle_min_ms: Option<u64>,
start: StreamId,
end: StreamId,
count: usize,
consumer_filter: Option<&[u8]>,
now_ms: u64,
) -> Option<PendingExtended> {
let g = self.groups.get(group)?;
let mut rows = Vec::with_capacity(count.min(g.pel.len()));
let span =
if start <= end { g.pel.range(start..=end) } else { g.pel.range(..StreamId::MIN) };
for (id, p) in span {
if rows.len() >= count {
break;
}
let idle = now_ms.saturating_sub(p.delivery_time_ms);
if let Some(min) = idle_min_ms
&& idle < min
{
continue;
}
if let Some(c) = consumer_filter
&& p.consumer.as_slice() != c
{
continue;
}
rows.push(PendingExtendedRow {
id: *id,
consumer: p.consumer.to_vec(),
idle_ms: idle,
delivery_count: p.delivery_count,
});
}
Some(PendingExtended { rows })
}
}