1use serde::Deserialize;
2
3#[derive(Debug, Deserialize)]
8pub struct WarpLimitInfoResponse {
9 pub data: WarpLimitData,
10}
11
12#[derive(Debug, Deserialize)]
13pub struct WarpLimitData {
14 #[serde(rename = "getRequestLimitInfo")]
15 pub get_request_limit_info: WarpRequestLimitInfo,
16}
17
18#[derive(Debug, Deserialize)]
20pub struct WarpRequestLimitInfo {
21 pub limit: i64,
23 pub used: i64,
25 #[serde(rename = "resetInSeconds")]
27 pub reset_in_seconds: Option<i64>,
28}
29
30impl WarpRequestLimitInfo {
31 #[must_use]
33 pub fn is_limited(&self) -> bool {
34 self.used >= self.limit
35 }
36
37 #[must_use]
40 #[expect(clippy::cast_precision_loss)]
41 pub fn utilization(&self) -> f64 {
42 if self.limit > 0 {
43 self.used as f64 / self.limit as f64 * 100.0
44 } else {
45 100.0
46 }
47 }
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53
54 type TestResult = Result<(), Box<dyn std::error::Error>>;
55
56 #[test]
57 fn test_deserialize_full_graphql_response() -> TestResult {
58 let json = r#"{
59 "data": {
60 "getRequestLimitInfo": {
61 "limit": 50,
62 "used": 10,
63 "resetInSeconds": 3600
64 }
65 }
66 }"#;
67
68 let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
69 let info = &response.data.get_request_limit_info;
70 assert_eq!(info.limit, 50);
71 assert_eq!(info.used, 10);
72 assert_eq!(info.reset_in_seconds, Some(3600));
73 Ok(())
74 }
75
76 #[test]
77 fn test_is_not_limited_when_below_limit() -> TestResult {
78 let json = r#"{
79 "data": {
80 "getRequestLimitInfo": {
81 "limit": 50,
82 "used": 10,
83 "resetInSeconds": 3600
84 }
85 }
86 }"#;
87
88 let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
89 assert!(!response.data.get_request_limit_info.is_limited());
90 Ok(())
91 }
92
93 #[test]
94 fn test_is_limited_when_used_equals_limit() -> TestResult {
95 let json = r#"{
96 "data": {
97 "getRequestLimitInfo": {
98 "limit": 50,
99 "used": 50,
100 "resetInSeconds": null
101 }
102 }
103 }"#;
104
105 let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
106 assert!(response.data.get_request_limit_info.is_limited());
107 Ok(())
108 }
109
110 #[test]
111 fn test_is_limited_when_used_exceeds_limit() -> TestResult {
112 let json = r#"{
113 "data": {
114 "getRequestLimitInfo": {
115 "limit": 10,
116 "used": 15,
117 "resetInSeconds": null
118 }
119 }
120 }"#;
121
122 let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
123 assert!(response.data.get_request_limit_info.is_limited());
124 Ok(())
125 }
126
127 #[test]
128 fn test_utilization_computed_correctly() {
129 let info = WarpRequestLimitInfo {
130 limit: 200,
131 used: 50,
132 reset_in_seconds: None,
133 };
134 assert!((info.utilization() - 25.0).abs() < f64::EPSILON);
135 }
136
137 #[test]
138 fn test_utilization_returns_100_when_zero_limit() {
139 let info = WarpRequestLimitInfo {
140 limit: 0,
141 used: 0,
142 reset_in_seconds: None,
143 };
144 assert!((info.utilization() - 100.0).abs() < f64::EPSILON);
145 }
146
147 #[test]
148 fn test_reset_in_seconds_is_optional() -> TestResult {
149 let json = r#"{
150 "data": {
151 "getRequestLimitInfo": {
152 "limit": 100,
153 "used": 0
154 }
155 }
156 }"#;
157
158 let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
159 assert!(
160 response
161 .data
162 .get_request_limit_info
163 .reset_in_seconds
164 .is_none()
165 );
166 Ok(())
167 }
168}