#![allow(dead_code)]
use std::{
fmt::{self, Write as _},
time::Duration,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub enum PressureLevel {
Low,
Medium,
High,
}
impl PressureLevel {
const MEDIUM_THRESHOLD: f64 = 0.75;
const HIGH_THRESHOLD: f64 = 1.0;
fn from_fraction(fraction: f64) -> Self {
if !fraction.is_finite() || fraction < Self::MEDIUM_THRESHOLD {
PressureLevel::Low
} else if fraction < Self::HIGH_THRESHOLD {
PressureLevel::Medium
} else {
PressureLevel::High
}
}
pub fn label(self) -> &'static str {
match self {
PressureLevel::Low => "low",
PressureLevel::Medium => "medium",
PressureLevel::High => "high",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct ResourceTelemetry {
pub tokens_used: u64,
pub time_used_seconds: u64,
pub token_budget: Option<u64>,
pub time_budget_seconds: Option<u64>,
}
impl ResourceTelemetry {
pub fn new(tokens_used: u64, time_used_seconds: u64) -> Self {
Self {
tokens_used,
time_used_seconds,
token_budget: None,
time_budget_seconds: None,
}
}
pub fn with_token_budget(mut self, budget: u64) -> Self {
self.token_budget = Some(budget);
self
}
pub fn with_time_budget_seconds(mut self, seconds: u64) -> Self {
self.time_budget_seconds = Some(seconds);
self
}
pub fn token_fraction(&self) -> Option<f64> {
fraction(self.tokens_used, self.token_budget)
}
pub fn time_fraction(&self) -> Option<f64> {
fraction(self.time_used_seconds, self.time_budget_seconds)
}
pub fn budget_fraction(&self) -> Option<f64> {
match (self.token_fraction(), self.time_fraction()) {
(Some(t), Some(s)) => Some(t.max(s)),
(Some(t), None) => Some(t),
(None, Some(s)) => Some(s),
(None, None) => None,
}
}
pub fn budget_percent(&self) -> Option<u64> {
self.budget_fraction().map(|f| (f * 100.0).round() as u64)
}
pub fn pressure(&self) -> PressureLevel {
match self.budget_fraction() {
Some(fraction) => PressureLevel::from_fraction(fraction),
None => PressureLevel::Low,
}
}
pub fn human_summary(&self) -> String {
let mut out = String::new();
let _ = write!(
out,
"{} tok · {}",
format_tokens(self.tokens_used),
crate::elapsed::format_elapsed_secs(self.time_used_seconds),
);
if let Some(percent) = self.budget_percent() {
let _ = write!(out, " · {percent}% budget");
}
out
}
}
impl fmt::Display for ResourceTelemetry {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(&self.human_summary())
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TokenThroughput {
pub output_tokens: u64,
pub elapsed_seconds: f64,
}
impl TokenThroughput {
pub fn new(output_tokens: u64, elapsed: Duration) -> Option<Self> {
let elapsed_seconds = elapsed.as_secs_f64();
if output_tokens == 0 || !elapsed_seconds.is_finite() || elapsed_seconds <= 0.0 {
return None;
}
Some(Self {
output_tokens,
elapsed_seconds,
})
}
pub fn from_estimated_text(text: &str, elapsed: Duration) -> Option<Self> {
Self::new(estimate_output_tokens_from_text(text), elapsed)
}
pub fn tokens_per_second(self) -> f64 {
self.output_tokens as f64 / self.elapsed_seconds
}
pub fn compact_rate(self) -> String {
let rate = self.tokens_per_second();
if rate < 10.0 {
format!("{rate:.1}")
} else {
format!("{rate:.0}")
}
}
}
pub fn estimate_output_tokens_from_text(text: &str) -> u64 {
let chars = text.chars().count() as u64;
if chars == 0 {
0
} else {
chars.saturating_add(3) / 4
}
}
fn fraction(used: u64, budget: Option<u64>) -> Option<f64> {
match budget {
Some(budget) if budget > 0 => Some(used as f64 / budget as f64),
_ => None,
}
}
fn format_tokens(tokens: u64) -> String {
const K: u64 = 1_000;
const M: u64 = 1_000_000;
if tokens >= M {
format_scaled(tokens, M, 'M')
} else if tokens >= K {
format_scaled(tokens, K, 'k')
} else {
tokens.to_string()
}
}
fn format_scaled(value: u64, divisor: u64, suffix: char) -> String {
let scaled = value as f64 / divisor as f64;
let rounded = (scaled * 10.0).round() / 10.0;
if (rounded.fract()).abs() < f64::EPSILON {
format!("{}{}", rounded as u64, suffix)
} else {
format!("{rounded:.1}{suffix}")
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_tokens_under_a_thousand_is_verbatim() {
assert_eq!(format_tokens(0), "0");
assert_eq!(format_tokens(1), "1");
assert_eq!(format_tokens(999), "999");
}
#[test]
fn format_tokens_uses_k_suffix_with_trimmed_decimal() {
assert_eq!(format_tokens(1_000), "1k");
assert_eq!(format_tokens(1_500), "1.5k");
assert_eq!(format_tokens(12_345), "12.3k");
assert_eq!(format_tokens(5_000), "5k");
assert_eq!(format_tokens(999_400), "999.4k");
}
#[test]
fn format_tokens_uses_m_suffix_for_millions() {
assert_eq!(format_tokens(1_000_000), "1M");
assert_eq!(format_tokens(1_500_000), "1.5M");
assert_eq!(format_tokens(2_340_000), "2.3M");
}
#[test]
fn format_tokens_rounds_up_across_a_unit_boundary() {
assert_eq!(format_tokens(1_999_999), "2M");
assert_eq!(format_tokens(999_950), "1000k");
}
#[test]
fn format_tokens_handles_very_large_values() {
assert_eq!(format_tokens(u64::MAX), "18446744073709.6M");
}
#[test]
fn token_throughput_formats_compact_rates() {
let throughput = TokenThroughput::new(120, Duration::from_secs(6)).expect("throughput");
assert_eq!(throughput.tokens_per_second(), 20.0);
assert_eq!(throughput.compact_rate(), "20");
let slow = TokenThroughput::new(15, Duration::from_secs(4)).expect("throughput");
assert_eq!(slow.compact_rate(), "3.8");
}
#[test]
fn token_throughput_rejects_empty_or_zero_elapsed_samples() {
assert!(TokenThroughput::new(0, Duration::from_secs(5)).is_none());
assert!(TokenThroughput::new(5, Duration::ZERO).is_none());
}
#[test]
fn estimated_streaming_tokens_round_up_from_text_chars() {
assert_eq!(estimate_output_tokens_from_text(""), 0);
assert_eq!(estimate_output_tokens_from_text("abc"), 1);
assert_eq!(estimate_output_tokens_from_text("abcd"), 1);
assert_eq!(estimate_output_tokens_from_text("abcde"), 2);
let throughput =
TokenThroughput::from_estimated_text(&"x".repeat(400), Duration::from_secs(10))
.expect("estimated throughput");
assert_eq!(throughput.output_tokens, 100);
assert_eq!(throughput.compact_rate(), "10");
}
#[test]
fn fractions_are_none_when_unbounded() {
let t = ResourceTelemetry::new(5_000, 120);
assert_eq!(t.token_fraction(), None);
assert_eq!(t.time_fraction(), None);
assert_eq!(t.budget_fraction(), None);
assert_eq!(t.budget_percent(), None);
}
#[test]
fn zero_budget_yields_none_not_infinity() {
let t = ResourceTelemetry {
tokens_used: 100,
time_used_seconds: 0,
token_budget: Some(0),
time_budget_seconds: Some(0),
};
assert_eq!(t.token_fraction(), None);
assert_eq!(t.time_fraction(), None);
assert_eq!(t.budget_fraction(), None);
assert_eq!(t.pressure(), PressureLevel::Low);
}
#[test]
fn token_fraction_is_computed_when_bounded() {
let t = ResourceTelemetry::new(4_100, 0).with_token_budget(10_000);
let frac = t.token_fraction().expect("bounded");
assert!((frac - 0.41).abs() < 1e-9, "got {frac}");
assert_eq!(t.budget_percent(), Some(41));
}
#[test]
fn budget_fraction_takes_the_max_across_dimensions() {
let t = ResourceTelemetry {
tokens_used: 1_000,
time_used_seconds: 80,
token_budget: Some(10_000),
time_budget_seconds: Some(100),
};
let frac = t.budget_fraction().expect("bounded");
assert!((frac - 0.80).abs() < 1e-9, "got {frac}");
assert_eq!(t.budget_percent(), Some(80));
}
#[test]
fn budget_fraction_present_when_only_one_dimension_bounded() {
let only_time = ResourceTelemetry::new(9_999, 50).with_time_budget_seconds(200);
assert_eq!(only_time.budget_percent(), Some(25));
let only_tokens = ResourceTelemetry::new(2_500, 9_999).with_token_budget(10_000);
assert_eq!(only_tokens.budget_percent(), Some(25));
}
#[test]
fn budget_percent_rounds_to_nearest_whole() {
let down = ResourceTelemetry::new(333, 0).with_token_budget(1_000);
assert_eq!(down.budget_percent(), Some(33));
let up = ResourceTelemetry::new(336, 0).with_token_budget(1_000);
assert_eq!(up.budget_percent(), Some(34));
}
#[test]
fn pressure_low_when_unbounded_regardless_of_usage() {
let t = ResourceTelemetry::new(u64::MAX, u64::MAX);
assert_eq!(t.pressure(), PressureLevel::Low);
}
#[test]
fn pressure_thresholds_just_under_and_over() {
let low = ResourceTelemetry::new(7_400, 0).with_token_budget(10_000);
assert_eq!(low.pressure(), PressureLevel::Low);
let medium_edge = ResourceTelemetry::new(7_500, 0).with_token_budget(10_000);
assert_eq!(medium_edge.pressure(), PressureLevel::Medium);
let medium = ResourceTelemetry::new(9_900, 0).with_token_budget(10_000);
assert_eq!(medium.pressure(), PressureLevel::Medium);
let high_edge = ResourceTelemetry::new(10_000, 0).with_token_budget(10_000);
assert_eq!(high_edge.pressure(), PressureLevel::High);
let over = ResourceTelemetry::new(12_500, 0).with_token_budget(10_000);
assert_eq!(over.pressure(), PressureLevel::High);
}
#[test]
fn pressure_level_labels_and_ordering() {
assert_eq!(PressureLevel::Low.label(), "low");
assert_eq!(PressureLevel::Medium.label(), "medium");
assert_eq!(PressureLevel::High.label(), "high");
assert!(PressureLevel::Low < PressureLevel::Medium);
assert!(PressureLevel::Medium < PressureLevel::High);
}
#[test]
fn pressure_from_fraction_ignores_non_finite() {
assert_eq!(PressureLevel::from_fraction(f64::NAN), PressureLevel::Low);
assert_eq!(
PressureLevel::from_fraction(f64::INFINITY),
PressureLevel::Low
);
assert_eq!(PressureLevel::from_fraction(-0.5), PressureLevel::Low);
}
#[test]
fn human_summary_bounded_matches_example_shape() {
let t = ResourceTelemetry::new(12_345, 252).with_token_budget(30_000);
assert_eq!(t.human_summary(), "12.3k tok · 4m 12s · 41% budget");
}
#[test]
fn human_summary_unbounded_omits_budget_segment() {
let t = ResourceTelemetry::new(500, 5);
assert_eq!(t.human_summary(), "500 tok · 5s");
assert_eq!(t.to_string(), "500 tok · 5s");
}
#[test]
fn human_summary_zero_everything() {
let t = ResourceTelemetry::default();
assert_eq!(t.human_summary(), "0 tok · 0s");
}
#[test]
fn human_summary_over_budget_can_exceed_one_hundred_percent() {
let t = ResourceTelemetry::new(15_000, 7_320).with_token_budget(10_000);
assert_eq!(t.human_summary(), "15k tok · 122m 00s · 150% budget");
assert_eq!(t.pressure(), PressureLevel::High);
}
#[test]
fn human_summary_with_only_time_budget() {
let t = ResourceTelemetry::new(2_000_000, 300).with_time_budget_seconds(600);
assert_eq!(t.human_summary(), "2M tok · 5m 00s · 50% budget");
assert_eq!(t.pressure(), PressureLevel::Low);
}
}