Skip to main content

weatherkit/
current_weather.rs

1//! WeatherKit current weather types.
2
3use 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/// Represents WeatherKit cloud cover by altitude.
15#[derive(Debug, Clone, PartialEq, Deserialize)]
16#[serde(rename_all = "camelCase")]
17pub struct CloudCoverByAltitude {
18    /// Matches the WeatherKit low value.
19    pub low: f64,
20    /// Matches the WeatherKit medium value.
21    pub medium: f64,
22    /// Matches the WeatherKit high value.
23    pub high: f64,
24}
25
26/// Represents the WeatherKit `WindCompassDirection` value.
27#[derive(Debug, Clone, PartialEq, Eq)]
28#[non_exhaustive]
29pub enum WindCompassDirection {
30    /// Matches the WeatherKit `North` case.
31    North,
32    /// Matches the WeatherKit `NorthNortheast` case.
33    NorthNortheast,
34    /// Matches the WeatherKit `Northeast` case.
35    Northeast,
36    /// Matches the WeatherKit `EastNortheast` case.
37    EastNortheast,
38    /// Matches the WeatherKit `East` case.
39    East,
40    /// Matches the WeatherKit `EastSoutheast` case.
41    EastSoutheast,
42    /// Matches the WeatherKit `Southeast` case.
43    Southeast,
44    /// Matches the WeatherKit `SouthSoutheast` case.
45    SouthSoutheast,
46    /// Matches the WeatherKit `South` case.
47    South,
48    /// Matches the WeatherKit `SouthSouthwest` case.
49    SouthSouthwest,
50    /// Matches the WeatherKit `Southwest` case.
51    Southwest,
52    /// Matches the WeatherKit `WestSouthwest` case.
53    WestSouthwest,
54    /// Matches the WeatherKit `West` case.
55    West,
56    /// Matches the WeatherKit `WestNorthwest` case.
57    WestNorthwest,
58    /// Matches the WeatherKit `Northwest` case.
59    Northwest,
60    /// Matches the WeatherKit `NorthNorthwest` case.
61    NorthNorthwest,
62    /// Stores an unrecognized WeatherKit case name.
63    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    /// Returns the WeatherKit raw value for this case.
90    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    /// Returns the WeatherKit descriptor catalog for this enum.
113    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/// Represents the WeatherKit `WindCompassDirectionDescriptor` payload.
122#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
123#[serde(rename_all = "camelCase")]
124pub struct WindCompassDirectionDescriptor {
125    /// Matches the WeatherKit raw value value.
126    pub raw_value: String,
127    /// Matches the WeatherKit abbreviation value.
128    pub abbreviation: String,
129    /// Matches the WeatherKit description value.
130    pub description: String,
131    /// Matches the WeatherKit accessibility description value.
132    pub accessibility_description: String,
133}
134
135/// Represents a WeatherKit wind reading.
136#[derive(Debug, Clone, PartialEq, Deserialize)]
137#[serde(rename_all = "camelCase")]
138pub struct Wind {
139    /// Matches the WeatherKit speed value.
140    pub speed: f64,
141    /// Matches the WeatherKit direction value.
142    pub direction: f64,
143    /// Matches the WeatherKit compass direction value.
144    pub compass_direction: String,
145    /// Matches the WeatherKit gust value.
146    pub gust: Option<f64>,
147}
148
149impl Wind {
150    /// Returns the WeatherKit compass direction enum for this wind.
151    pub fn compass_direction_kind(&self) -> WindCompassDirection {
152        WindCompassDirection::from_raw(self.compass_direction.clone())
153    }
154}
155
156/// Represents the WeatherKit `UVExposureCategory` value.
157#[derive(Debug, Clone, PartialEq, Eq)]
158#[non_exhaustive]
159pub enum UVExposureCategory {
160    /// Matches the WeatherKit `Low` case.
161    Low,
162    /// Matches the WeatherKit `Moderate` case.
163    Moderate,
164    /// Matches the WeatherKit `High` case.
165    High,
166    /// Matches the WeatherKit `VeryHigh` case.
167    VeryHigh,
168    /// Matches the WeatherKit `Extreme` case.
169    Extreme,
170    /// Stores an unrecognized WeatherKit case name.
171    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    /// Returns the WeatherKit raw value for this case.
187    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    /// Returns the WeatherKit descriptor catalog for this enum.
199    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/// Represents the WeatherKit `UVExposureCategoryDescriptor` payload.
208#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
209#[serde(rename_all = "camelCase")]
210pub struct UVExposureCategoryDescriptor {
211    /// Matches the WeatherKit raw value value.
212    pub raw_value: String,
213    /// Matches the WeatherKit description value.
214    pub description: String,
215    /// Matches the WeatherKit accessibility description value.
216    pub accessibility_description: String,
217    /// Matches the WeatherKit range start value.
218    pub range_start: i64,
219    /// Matches the WeatherKit range end value.
220    pub range_end: i64,
221}
222
223/// Represents a WeatherKit UV index reading.
224#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
225#[serde(rename_all = "camelCase")]
226pub struct UVIndex {
227    /// Matches the WeatherKit value value.
228    pub value: i64,
229    /// Matches the WeatherKit category value.
230    pub category: String,
231}
232
233impl UVIndex {
234    /// Returns the WeatherKit exposure category for this index.
235    pub fn exposure_category(&self) -> UVExposureCategory {
236        UVExposureCategory::from_raw(self.category.clone())
237    }
238}
239
240/// Wraps the WeatherKit current weather payload.
241#[derive(Debug, Clone, PartialEq, Deserialize)]
242#[serde(rename_all = "camelCase")]
243pub struct CurrentWeather {
244    /// Matches the WeatherKit date value.
245    pub date: String,
246    /// Matches the WeatherKit temperature value.
247    pub temperature: f64,
248    /// Matches the WeatherKit feels like value.
249    pub feels_like: f64,
250    /// Matches the WeatherKit humidity value.
251    pub humidity: f64,
252    /// Matches the WeatherKit dew point value.
253    pub dew_point: f64,
254    /// Matches the WeatherKit pressure value.
255    pub pressure: f64,
256    /// Matches the WeatherKit pressure trend value.
257    #[serde(deserialize_with = "deserialize_pressure_trend")]
258    pub pressure_trend: PressureTrend,
259    /// Matches the WeatherKit condition value.
260    #[serde(deserialize_with = "deserialize_weather_condition")]
261    pub condition: WeatherCondition,
262    /// Matches the WeatherKit symbol name value.
263    pub symbol_name: String,
264    /// Matches the WeatherKit wind value.
265    pub wind: Wind,
266    /// Matches the WeatherKit uv index value.
267    pub uv_index: UVIndex,
268    /// Matches the WeatherKit visibility value.
269    pub visibility: f64,
270    /// Matches the WeatherKit cloud cover value.
271    pub cloud_cover: f64,
272    /// Matches the WeatherKit cloud cover by altitude value.
273    #[serde(default)]
274    pub cloud_cover_by_altitude: Option<CloudCoverByAltitude>,
275    /// Matches the WeatherKit is daylight value.
276    pub is_daylight: bool,
277    /// Matches the WeatherKit precipitation intensity value.
278    pub precipitation_intensity: f64,
279    /// Matches the WeatherKit metadata value.
280    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    /// Wraps the WeatherKit pressure value and trend.
294    pub fn pressure_reading(&self) -> Pressure {
295        Pressure::new(self.pressure, self.pressure_trend.clone())
296    }
297}