use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct Usage {
pub input_tokens: usize,
pub output_tokens: usize,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_creation_input_tokens: Option<usize>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cache_read_input_tokens: Option<usize>,
}
impl Usage {
pub fn new(input_tokens: usize, output_tokens: usize) -> Self {
Self {
input_tokens,
output_tokens,
cache_creation_input_tokens: None,
cache_read_input_tokens: None,
}
}
pub fn total_tokens(&self) -> usize {
self.input_tokens + self.output_tokens
}
pub fn cached_tokens(&self) -> usize {
self.cache_creation_input_tokens.unwrap_or(0) + self.cache_read_input_tokens.unwrap_or(0)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_usage_new() {
let usage = Usage::new(100, 50);
assert_eq!(usage.input_tokens, 100);
assert_eq!(usage.output_tokens, 50);
assert_eq!(usage.total_tokens(), 150);
}
#[test]
fn test_usage_deserialize() {
let json = r#"{
"input_tokens": 100,
"output_tokens": 50,
"cache_creation_input_tokens": 10,
"cache_read_input_tokens": 20
}"#;
let usage: Usage = serde_json::from_str(json).unwrap();
assert_eq!(usage.input_tokens, 100);
assert_eq!(usage.output_tokens, 50);
assert_eq!(usage.cache_creation_input_tokens, Some(10));
assert_eq!(usage.cache_read_input_tokens, Some(20));
assert_eq!(usage.cached_tokens(), 30);
}
#[test]
fn test_usage_serialize() {
let usage = Usage::new(100, 50);
let json = serde_json::to_string(&usage).unwrap();
assert!(json.contains("\"input_tokens\":100"));
assert!(json.contains("\"output_tokens\":50"));
assert!(!json.contains("cache_creation_input_tokens"));
assert!(!json.contains("cache_read_input_tokens"));
}
}