Candifloss d8048daa51 Update struct WeatherResponse
- Better handling of missing fields
2025-10-09 13:36:52 +05:30

136 lines
3.3 KiB
Rust

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Coord {
pub lon: f64,
pub lat: f64,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Weather {
pub id: u32,
pub main: String,
pub description: String,
pub icon: String,
}
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Main {
pub temp: Option<f32>,
#[serde(default)]
pub feels_like: Option<f32>,
#[serde(default)]
pub temp_min: Option<f32>,
#[serde(default)]
pub temp_max: Option<f32>,
#[serde(default)]
pub pressure: Option<u32>,
#[serde(default)]
pub humidity: Option<u8>,
#[serde(default)]
pub sea_level: Option<u32>,
#[serde(default)]
pub grnd_level: Option<u32>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct Wind {
pub speed: Option<f32>,
pub deg: Option<u16>,
pub gust: Option<f32>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct Clouds {
pub all: Option<u8>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct Precipitation {
#[serde(rename = "1h", default)]
pub one_hour: Option<f32>,
#[serde(rename = "3h", default)]
pub three_hour: Option<f32>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct Sys {
pub r#type: Option<u8>,
pub id: Option<u32>,
pub country: Option<String>,
#[serde(with = "chrono::serde::ts_seconds_option")]
pub sunrise: Option<DateTime<Utc>>,
#[serde(with = "chrono::serde::ts_seconds_option")]
pub sunset: Option<DateTime<Utc>>,
pub message: Option<f64>,
}
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct WeatherResponse {
#[serde(default)]
pub coord: Option<Coord>,
#[serde(default)]
pub weather: Vec<Weather>,
#[serde(default)]
pub base: Option<String>,
#[serde(default)]
pub main: Option<Main>,
#[serde(default)]
pub visibility: Option<u32>,
#[serde(with = "chrono::serde::ts_seconds_option")]
pub dt: Option<DateTime<Utc>>,
#[serde(default)]
pub sys: Option<Sys>,
#[serde(default)]
pub timezone: Option<i32>,
#[serde(default)]
pub id: Option<u64>,
#[serde(default)]
pub name: Option<String>,
#[serde(default)]
pub wind: Option<Wind>,
#[serde(default)]
pub clouds: Option<Clouds>,
#[serde(default)]
pub rain: Option<Precipitation>,
#[serde(default)]
pub snow: Option<Precipitation>,
#[serde(default)]
pub cod: Option<u16>,
#[serde(default)]
pub message: Option<String>,
}
impl WeatherResponse {
pub fn primary_weather(&self) -> Option<&Weather> {
self.weather.first()
}
pub fn is_success(&self) -> bool {
matches!(self.cod, Some(200))
}
pub fn temperature(&self) -> Option<f32> {
self.main.as_ref().map(|m| m.temp)?
}
pub fn city(&self) -> Option<&str> {
self.name.as_deref()
}
pub fn country(&self) -> Option<&str> {
self.sys.as_ref()?.country.as_deref()
}
pub fn summary(&self) -> String {
let temp = self
.temperature()
.map_or("-".into(), |t| format!("{t:.1}°"));
let desc = self
.primary_weather()
.map_or("N/A", |w| w.description.as_str());
format!("{desc}, {temp}")
}
}