use serde::Deserialize;
use serde::Serialize;
use crate::json::JsonObject;
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct Usage {
#[serde(default)]
pub input: InputTokens,
#[serde(default)]
pub output: OutputTokens,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub raw: Option<JsonObject>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct InputTokens {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub no_cache: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_read: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub cache_write: Option<u64>,
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct OutputTokens {
#[serde(default, skip_serializing_if = "Option::is_none")]
pub total: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub text: Option<u64>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub reasoning: Option<u64>,
}
#[must_use]
pub fn add_token_counts(a: Option<u64>, b: Option<u64>) -> Option<u64> {
match (a, b) {
(None, None) => None,
(Some(a), None) => Some(a),
(None, Some(b)) => Some(b),
(Some(a), Some(b)) => Some(a.saturating_add(b)),
}
}
impl Usage {
#[must_use]
pub fn totals(input: u64, output: u64) -> Self {
Self {
input: InputTokens {
total: Some(input),
..InputTokens::default()
},
output: OutputTokens {
total: Some(output),
..OutputTokens::default()
},
raw: None,
}
}
#[must_use]
pub fn add(&self, other: &Usage) -> Usage {
Usage {
input: InputTokens {
total: add_token_counts(self.input.total, other.input.total),
no_cache: add_token_counts(self.input.no_cache, other.input.no_cache),
cache_read: add_token_counts(self.input.cache_read, other.input.cache_read),
cache_write: add_token_counts(self.input.cache_write, other.input.cache_write),
},
output: OutputTokens {
total: add_token_counts(self.output.total, other.output.total),
text: add_token_counts(self.output.text, other.output.text),
reasoning: add_token_counts(self.output.reasoning, other.output.reasoning),
},
raw: None,
}
}
#[must_use]
pub fn total_tokens(&self) -> Option<u64> {
add_token_counts(self.input.total, self.output.total)
}
}