use serde::Deserialize;
#[derive(Debug, Deserialize)]
pub struct WarpLimitInfoResponse {
pub data: WarpLimitData,
}
#[derive(Debug, Deserialize)]
pub struct WarpLimitData {
#[serde(rename = "getRequestLimitInfo")]
pub get_request_limit_info: WarpRequestLimitInfo,
}
#[derive(Debug, Deserialize)]
pub struct WarpRequestLimitInfo {
pub limit: i64,
pub used: i64,
#[serde(rename = "resetInSeconds")]
pub reset_in_seconds: Option<i64>,
}
impl WarpRequestLimitInfo {
#[must_use]
pub fn is_limited(&self) -> bool {
self.used >= self.limit
}
#[must_use]
#[expect(clippy::cast_precision_loss)]
pub fn utilization(&self) -> f64 {
if self.limit > 0 {
self.used as f64 / self.limit as f64 * 100.0
} else {
100.0
}
}
}
#[cfg(test)]
mod tests {
use super::*;
type TestResult = Result<(), Box<dyn std::error::Error>>;
#[test]
fn test_deserialize_full_graphql_response() -> TestResult {
let json = r#"{
"data": {
"getRequestLimitInfo": {
"limit": 50,
"used": 10,
"resetInSeconds": 3600
}
}
}"#;
let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
let info = &response.data.get_request_limit_info;
assert_eq!(info.limit, 50);
assert_eq!(info.used, 10);
assert_eq!(info.reset_in_seconds, Some(3600));
Ok(())
}
#[test]
fn test_is_not_limited_when_below_limit() -> TestResult {
let json = r#"{
"data": {
"getRequestLimitInfo": {
"limit": 50,
"used": 10,
"resetInSeconds": 3600
}
}
}"#;
let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
assert!(!response.data.get_request_limit_info.is_limited());
Ok(())
}
#[test]
fn test_is_limited_when_used_equals_limit() -> TestResult {
let json = r#"{
"data": {
"getRequestLimitInfo": {
"limit": 50,
"used": 50,
"resetInSeconds": null
}
}
}"#;
let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
assert!(response.data.get_request_limit_info.is_limited());
Ok(())
}
#[test]
fn test_is_limited_when_used_exceeds_limit() -> TestResult {
let json = r#"{
"data": {
"getRequestLimitInfo": {
"limit": 10,
"used": 15,
"resetInSeconds": null
}
}
}"#;
let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
assert!(response.data.get_request_limit_info.is_limited());
Ok(())
}
#[test]
fn test_utilization_computed_correctly() {
let info = WarpRequestLimitInfo {
limit: 200,
used: 50,
reset_in_seconds: None,
};
assert!((info.utilization() - 25.0).abs() < f64::EPSILON);
}
#[test]
fn test_utilization_returns_100_when_zero_limit() {
let info = WarpRequestLimitInfo {
limit: 0,
used: 0,
reset_in_seconds: None,
};
assert!((info.utilization() - 100.0).abs() < f64::EPSILON);
}
#[test]
fn test_reset_in_seconds_is_optional() -> TestResult {
let json = r#"{
"data": {
"getRequestLimitInfo": {
"limit": 100,
"used": 0
}
}
}"#;
let response: WarpLimitInfoResponse = serde_json::from_str(json)?;
assert!(
response
.data
.get_request_limit_info
.reset_in_seconds
.is_none()
);
Ok(())
}
}