use rust_decimal::Decimal;
use serde::Deserialize;
use serde::de::{self, Deserializer, IgnoredAny, MapAccess, SeqAccess, Visitor};
use serde_json::Value;
use std::fmt;
use super::types::NormalizedUsage;
pub(super) fn count(value: &Value, name: &str) -> Option<u64> {
value.get(name).and_then(Value::as_u64)
}
pub(super) fn present(value: &Value, name: &str) -> bool {
value.get(name).is_some_and(Value::is_u64)
}
pub(super) fn decimal(value: &Value) -> Option<Decimal> {
match value {
Value::Number(number) => number.to_string().parse().ok(),
Value::String(text) => text.parse().ok(),
_ => None,
}
}
pub(super) fn label(value: &Value) -> Option<String> {
if let Some(text) = value.as_str() {
return Some(text.to_owned());
}
let object = value.as_object()?;
object
.get("name")
.or_else(|| object.get("type"))?
.as_str()
.map(str::to_owned)
}
pub(super) fn metric(usage: &mut NormalizedUsage, name: &str, value: u64) {
if value > 0 {
usage.metrics.insert(name.into(), Decimal::from(value));
}
}
pub(super) fn service_tier(usage: &mut NormalizedUsage, tier: Option<String>) {
if let Some(tier) = tier.filter(|tier| !tier.is_empty()) {
usage.dimensions.insert("service_tier".into(), tier.clone());
usage.actual_service_tier = Some(tier);
}
}
pub(super) const MODALITIES_IN_TOTALS: &str = "token_modalities_in_totals";
pub(super) fn flag_modalities(usage: &mut NormalizedUsage) {
let modal = usage.metrics.keys().any(|key| {
[
"audio_",
"text_",
"image_",
"cached_audio_",
"cached_image_",
"cached_text_",
]
.iter()
.any(|prefix| key.starts_with(prefix))
&& key.ends_with("_tokens")
});
if modal {
usage
.dimensions
.insert(MODALITIES_IN_TOTALS.into(), "true".into());
}
}
pub(super) fn object<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<Value>, D::Error> {
Ok(Some(Value::deserialize(deserializer)?).filter(Value::is_object))
}
pub(super) fn any<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Option<Value>, D::Error> {
Ok(Some(Value::deserialize(deserializer)?).filter(|value| !value.is_null()))
}
pub(super) fn string<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<String>, D::Error> {
struct Text;
impl<'de> Visitor<'de> for Text {
type Value = Option<String>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("any JSON value")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Self::Value, E> {
Ok(Some(value.to_owned()))
}
fn visit_string<E: de::Error>(self, value: String) -> Result<Self::Value, E> {
Ok(Some(value))
}
fn visit_bool<E: de::Error>(self, _: bool) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_i64<E: de::Error>(self, _: i64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_u64<E: de::Error>(self, _: u64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_f64<E: de::Error>(self, _: f64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
while seq.next_element::<IgnoredAny>()?.is_some() {}
Ok(None)
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
while map.next_entry::<IgnoredAny, IgnoredAny>()?.is_some() {}
Ok(None)
}
}
deserializer.deserialize_any(Text)
}
pub(super) fn length<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Option<usize>, D::Error> {
struct Length;
impl<'de> Visitor<'de> for Length {
type Value = Option<usize>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("any JSON value")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut length = 0;
while seq.next_element::<IgnoredAny>()?.is_some() {
length += 1;
}
Ok(Some(length))
}
fn visit_map<A: MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
while map.next_entry::<IgnoredAny, IgnoredAny>()?.is_some() {}
Ok(None)
}
fn visit_str<E: de::Error>(self, _: &str) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_bool<E: de::Error>(self, _: bool) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_i64<E: de::Error>(self, _: i64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_u64<E: de::Error>(self, _: u64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_f64<E: de::Error>(self, _: f64) -> Result<Self::Value, E> {
Ok(None)
}
fn visit_unit<E: de::Error>(self) -> Result<Self::Value, E> {
Ok(None)
}
}
deserializer.deserialize_any(Length)
}