1use core::ffi::c_void;
4
5use serde::Deserialize;
6
7use crate::error::WeatherKitError;
8use crate::ffi;
9use crate::pressure::{deserialize_pressure_trend, Pressure, PressureTrend};
10use crate::private::{parse_json_from_handle, parse_json_from_static};
11use crate::service::WeatherMetadata;
12use crate::weather_condition::{deserialize_weather_condition, WeatherCondition};
13
14#[derive(Debug, Clone, PartialEq, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct CloudCoverByAltitude {
18 pub low: f64,
20 pub medium: f64,
22 pub high: f64,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28#[non_exhaustive]
29pub enum WindCompassDirection {
30 North,
32 NorthNortheast,
34 Northeast,
36 EastNortheast,
38 East,
40 EastSoutheast,
42 Southeast,
44 SouthSoutheast,
46 South,
48 SouthSouthwest,
50 Southwest,
52 WestSouthwest,
54 West,
56 WestNorthwest,
58 Northwest,
60 NorthNorthwest,
62 Unknown(String),
64}
65
66impl WindCompassDirection {
67 pub(crate) fn from_raw(value: String) -> Self {
68 match value.as_str() {
69 "north" => Self::North,
70 "northNortheast" => Self::NorthNortheast,
71 "northeast" => Self::Northeast,
72 "eastNortheast" => Self::EastNortheast,
73 "east" => Self::East,
74 "eastSoutheast" => Self::EastSoutheast,
75 "southeast" => Self::Southeast,
76 "southSoutheast" => Self::SouthSoutheast,
77 "south" => Self::South,
78 "southSouthwest" => Self::SouthSouthwest,
79 "southwest" => Self::Southwest,
80 "westSouthwest" => Self::WestSouthwest,
81 "west" => Self::West,
82 "westNorthwest" => Self::WestNorthwest,
83 "northwest" => Self::Northwest,
84 "northNorthwest" => Self::NorthNorthwest,
85 other => Self::Unknown(other.to_owned()),
86 }
87 }
88
89 pub fn raw_value(&self) -> &str {
91 match self {
92 Self::North => "north",
93 Self::NorthNortheast => "northNortheast",
94 Self::Northeast => "northeast",
95 Self::EastNortheast => "eastNortheast",
96 Self::East => "east",
97 Self::EastSoutheast => "eastSoutheast",
98 Self::Southeast => "southeast",
99 Self::SouthSoutheast => "southSoutheast",
100 Self::South => "south",
101 Self::SouthSouthwest => "southSouthwest",
102 Self::Southwest => "southwest",
103 Self::WestSouthwest => "westSouthwest",
104 Self::West => "west",
105 Self::WestNorthwest => "westNorthwest",
106 Self::Northwest => "northwest",
107 Self::NorthNorthwest => "northNorthwest",
108 Self::Unknown(value) => value.as_str(),
109 }
110 }
111
112 pub fn descriptors() -> Result<Vec<WindCompassDirectionDescriptor>, WeatherKitError> {
114 parse_json_from_static(
115 ffi::current_weather::wk_wind_compass_direction_copy_descriptors_json,
116 "wind compass direction descriptors",
117 )
118 }
119}
120
121#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
123#[serde(rename_all = "camelCase")]
124pub struct WindCompassDirectionDescriptor {
125 pub raw_value: String,
127 pub abbreviation: String,
129 pub description: String,
131 pub accessibility_description: String,
133}
134
135#[derive(Debug, Clone, PartialEq, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct Wind {
139 pub speed: f64,
141 pub direction: f64,
143 pub compass_direction: String,
145 pub gust: Option<f64>,
147}
148
149impl Wind {
150 pub fn compass_direction_kind(&self) -> WindCompassDirection {
152 WindCompassDirection::from_raw(self.compass_direction.clone())
153 }
154}
155
156#[derive(Debug, Clone, PartialEq, Eq)]
158#[non_exhaustive]
159pub enum UVExposureCategory {
160 Low,
162 Moderate,
164 High,
166 VeryHigh,
168 Extreme,
170 Unknown(String),
172}
173
174impl UVExposureCategory {
175 pub(crate) fn from_raw(value: String) -> Self {
176 match value.as_str() {
177 "low" => Self::Low,
178 "moderate" => Self::Moderate,
179 "high" => Self::High,
180 "veryHigh" => Self::VeryHigh,
181 "extreme" => Self::Extreme,
182 other => Self::Unknown(other.to_owned()),
183 }
184 }
185
186 pub fn raw_value(&self) -> &str {
188 match self {
189 Self::Low => "low",
190 Self::Moderate => "moderate",
191 Self::High => "high",
192 Self::VeryHigh => "veryHigh",
193 Self::Extreme => "extreme",
194 Self::Unknown(value) => value.as_str(),
195 }
196 }
197
198 pub fn descriptors() -> Result<Vec<UVExposureCategoryDescriptor>, WeatherKitError> {
200 parse_json_from_static(
201 ffi::current_weather::wk_uv_exposure_category_copy_descriptors_json,
202 "UV exposure category descriptors",
203 )
204 }
205}
206
207#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct UVExposureCategoryDescriptor {
211 pub raw_value: String,
213 pub description: String,
215 pub accessibility_description: String,
217 pub range_start: i64,
219 pub range_end: i64,
221}
222
223#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct UVIndex {
227 pub value: i64,
229 pub category: String,
231}
232
233impl UVIndex {
234 pub fn exposure_category(&self) -> UVExposureCategory {
236 UVExposureCategory::from_raw(self.category.clone())
237 }
238}
239
240#[derive(Debug, Clone, PartialEq, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct CurrentWeather {
244 pub date: String,
246 pub temperature: f64,
248 pub feels_like: f64,
250 pub humidity: f64,
252 pub dew_point: f64,
254 pub pressure: f64,
256 #[serde(deserialize_with = "deserialize_pressure_trend")]
258 pub pressure_trend: PressureTrend,
259 #[serde(deserialize_with = "deserialize_weather_condition")]
261 pub condition: WeatherCondition,
262 pub symbol_name: String,
264 pub wind: Wind,
266 pub uv_index: UVIndex,
268 pub visibility: f64,
270 pub cloud_cover: f64,
272 #[serde(default)]
274 pub cloud_cover_by_altitude: Option<CloudCoverByAltitude>,
275 pub is_daylight: bool,
277 pub precipitation_intensity: f64,
279 pub metadata: WeatherMetadata,
281}
282
283impl CurrentWeather {
284 pub(crate) fn from_owned_ptr(ptr: *mut c_void) -> Result<Self, WeatherKitError> {
285 parse_json_from_handle(
286 ptr,
287 ffi::current_weather::wk_current_weather_release,
288 ffi::current_weather::wk_current_weather_copy_json,
289 "current weather",
290 )
291 }
292
293 pub fn pressure_reading(&self) -> Pressure {
295 Pressure::new(self.pressure, self.pressure_trend.clone())
296 }
297}