pub mod claude;
pub mod codex;
pub mod gemini;
pub mod grok;
pub mod opencode;
pub mod pi;
pub mod prince;
use crate::error::AppError;
use crate::model::{AppKind, UsageEntry};
pub fn fresh_input(input: u64, cache_read: u64, cache_creation: u64) -> u64 {
input
.checked_sub(cache_read.saturating_add(cache_creation))
.unwrap_or(input)
}
pub fn collect(apps: &[AppKind]) -> Result<Vec<UsageEntry>, AppError> {
let mut entries = Vec::new();
for &app in apps {
match app {
AppKind::Claude => entries.extend(claude::collect()?),
AppKind::Codex => entries.extend(codex::collect()?),
AppKind::OpenCode => entries.extend(opencode::collect()?),
AppKind::Gemini => entries.extend(gemini::collect()?),
AppKind::Grok => entries.extend(grok::collect()?),
AppKind::Pi => entries.extend(pi::collect()?),
}
}
Ok(entries)
}
#[cfg(test)]
mod tests {
use super::fresh_input;
#[test]
fn test_fresh_input() {
assert_eq!(fresh_input(100, 50, 0), 50);
assert_eq!(fresh_input(100, 50, 20), 30);
assert_eq!(fresh_input(50, 0, 0), 50);
assert_eq!(fresh_input(10, 20, 0), 10); }
}