1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4#[derive(Debug, Deserialize, Serialize)]
5pub struct UsageWindow {
6 pub utilization: Option<f64>,
7 pub resets_at: Option<DateTime<Utc>>,
8}
9
10impl UsageWindow {
11 #[must_use]
12 pub fn is_limited(&self) -> bool {
13 self.utilization.unwrap_or(0.0) >= 100.0
14 }
15}
16
17#[derive(Debug, Deserialize, Serialize)]
18pub struct UsageResponse {
19 pub five_hour: Option<UsageWindow>,
20 pub seven_day: Option<UsageWindow>,
21 pub seven_day_sonnet: Option<UsageWindow>,
22 pub seven_day_oauth_apps: Option<UsageWindow>,
23 pub seven_day_opus: Option<UsageWindow>,
24 pub seven_day_cowork: Option<UsageWindow>,
25 pub iguana_necktie: Option<UsageWindow>,
26 pub extra_usage: Option<UsageWindow>,
27}
28
29impl UsageResponse {
30 #[must_use]
32 pub fn all_windows(&self) -> Vec<(&str, &UsageWindow)> {
33 [
34 ("five_hour", self.five_hour.as_ref()),
35 ("seven_day", self.seven_day.as_ref()),
36 ("seven_day_sonnet", self.seven_day_sonnet.as_ref()),
37 ("seven_day_oauth_apps", self.seven_day_oauth_apps.as_ref()),
38 ("seven_day_opus", self.seven_day_opus.as_ref()),
39 ("seven_day_cowork", self.seven_day_cowork.as_ref()),
40 ("iguana_necktie", self.iguana_necktie.as_ref()),
41 ("extra_usage", self.extra_usage.as_ref()),
42 ]
43 .into_iter()
44 .filter_map(|(name, w)| w.map(|w| (name, w)))
45 .collect()
46 }
47
48 #[must_use]
49 pub fn next_reset_time(&self) -> Option<chrono::DateTime<Utc>> {
50 self.all_windows()
51 .into_iter()
52 .filter(|(_, w)| w.is_limited())
53 .filter_map(|(_, w)| w.resets_at)
54 .max()
55 }
56}