Skip to main content

weatherkit/
current_weather.rs

1use core::ffi::c_void;
2
3use serde::Deserialize;
4
5use crate::error::WeatherKitError;
6use crate::ffi;
7use crate::pressure::{deserialize_pressure_trend, Pressure, PressureTrend};
8use crate::private::{parse_json_from_handle, parse_json_from_static};
9use crate::service::WeatherMetadata;
10use crate::weather_condition::{deserialize_weather_condition, WeatherCondition};
11
12#[derive(Debug, Clone, PartialEq, Deserialize)]
13#[serde(rename_all = "camelCase")]
14pub struct CloudCoverByAltitude {
15    pub low: f64,
16    pub medium: f64,
17    pub high: f64,
18}
19
20#[derive(Debug, Clone, PartialEq, Eq)]
21#[non_exhaustive]
22pub enum WindCompassDirection {
23    North,
24    NorthNortheast,
25    Northeast,
26    EastNortheast,
27    East,
28    EastSoutheast,
29    Southeast,
30    SouthSoutheast,
31    South,
32    SouthSouthwest,
33    Southwest,
34    WestSouthwest,
35    West,
36    WestNorthwest,
37    Northwest,
38    NorthNorthwest,
39    Unknown(String),
40}
41
42impl WindCompassDirection {
43    pub(crate) fn from_raw(value: String) -> Self {
44        match value.as_str() {
45            "north" => Self::North,
46            "northNortheast" => Self::NorthNortheast,
47            "northeast" => Self::Northeast,
48            "eastNortheast" => Self::EastNortheast,
49            "east" => Self::East,
50            "eastSoutheast" => Self::EastSoutheast,
51            "southeast" => Self::Southeast,
52            "southSoutheast" => Self::SouthSoutheast,
53            "south" => Self::South,
54            "southSouthwest" => Self::SouthSouthwest,
55            "southwest" => Self::Southwest,
56            "westSouthwest" => Self::WestSouthwest,
57            "west" => Self::West,
58            "westNorthwest" => Self::WestNorthwest,
59            "northwest" => Self::Northwest,
60            "northNorthwest" => Self::NorthNorthwest,
61            other => Self::Unknown(other.to_owned()),
62        }
63    }
64
65    pub fn raw_value(&self) -> &str {
66        match self {
67            Self::North => "north",
68            Self::NorthNortheast => "northNortheast",
69            Self::Northeast => "northeast",
70            Self::EastNortheast => "eastNortheast",
71            Self::East => "east",
72            Self::EastSoutheast => "eastSoutheast",
73            Self::Southeast => "southeast",
74            Self::SouthSoutheast => "southSoutheast",
75            Self::South => "south",
76            Self::SouthSouthwest => "southSouthwest",
77            Self::Southwest => "southwest",
78            Self::WestSouthwest => "westSouthwest",
79            Self::West => "west",
80            Self::WestNorthwest => "westNorthwest",
81            Self::Northwest => "northwest",
82            Self::NorthNorthwest => "northNorthwest",
83            Self::Unknown(value) => value.as_str(),
84        }
85    }
86
87    pub fn descriptors() -> Result<Vec<WindCompassDirectionDescriptor>, WeatherKitError> {
88        parse_json_from_static(
89            ffi::current_weather::wk_wind_compass_direction_copy_descriptors_json,
90            "wind compass direction descriptors",
91        )
92    }
93}
94
95#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
96#[serde(rename_all = "camelCase")]
97pub struct WindCompassDirectionDescriptor {
98    pub raw_value: String,
99    pub abbreviation: String,
100    pub description: String,
101    pub accessibility_description: String,
102}
103
104#[derive(Debug, Clone, PartialEq, Deserialize)]
105#[serde(rename_all = "camelCase")]
106pub struct Wind {
107    pub speed: f64,
108    pub direction: f64,
109    pub compass_direction: String,
110    pub gust: Option<f64>,
111}
112
113impl Wind {
114    pub fn compass_direction_kind(&self) -> WindCompassDirection {
115        WindCompassDirection::from_raw(self.compass_direction.clone())
116    }
117}
118
119#[derive(Debug, Clone, PartialEq, Eq)]
120#[non_exhaustive]
121pub enum UVExposureCategory {
122    Low,
123    Moderate,
124    High,
125    VeryHigh,
126    Extreme,
127    Unknown(String),
128}
129
130impl UVExposureCategory {
131    pub(crate) fn from_raw(value: String) -> Self {
132        match value.as_str() {
133            "low" => Self::Low,
134            "moderate" => Self::Moderate,
135            "high" => Self::High,
136            "veryHigh" => Self::VeryHigh,
137            "extreme" => Self::Extreme,
138            other => Self::Unknown(other.to_owned()),
139        }
140    }
141
142    pub fn raw_value(&self) -> &str {
143        match self {
144            Self::Low => "low",
145            Self::Moderate => "moderate",
146            Self::High => "high",
147            Self::VeryHigh => "veryHigh",
148            Self::Extreme => "extreme",
149            Self::Unknown(value) => value.as_str(),
150        }
151    }
152
153    pub fn descriptors() -> Result<Vec<UVExposureCategoryDescriptor>, WeatherKitError> {
154        parse_json_from_static(
155            ffi::current_weather::wk_uv_exposure_category_copy_descriptors_json,
156            "UV exposure category descriptors",
157        )
158    }
159}
160
161#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
162#[serde(rename_all = "camelCase")]
163pub struct UVExposureCategoryDescriptor {
164    pub raw_value: String,
165    pub description: String,
166    pub accessibility_description: String,
167    pub range_start: i64,
168    pub range_end: i64,
169}
170
171#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
172#[serde(rename_all = "camelCase")]
173pub struct UVIndex {
174    pub value: i64,
175    pub category: String,
176}
177
178impl UVIndex {
179    pub fn exposure_category(&self) -> UVExposureCategory {
180        UVExposureCategory::from_raw(self.category.clone())
181    }
182}
183
184#[derive(Debug, Clone, PartialEq, Deserialize)]
185#[serde(rename_all = "camelCase")]
186pub struct CurrentWeather {
187    pub date: String,
188    pub temperature: f64,
189    pub feels_like: f64,
190    pub humidity: f64,
191    pub dew_point: f64,
192    pub pressure: f64,
193    #[serde(deserialize_with = "deserialize_pressure_trend")]
194    pub pressure_trend: PressureTrend,
195    #[serde(deserialize_with = "deserialize_weather_condition")]
196    pub condition: WeatherCondition,
197    pub symbol_name: String,
198    pub wind: Wind,
199    pub uv_index: UVIndex,
200    pub visibility: f64,
201    pub cloud_cover: f64,
202    #[serde(default)]
203    pub cloud_cover_by_altitude: Option<CloudCoverByAltitude>,
204    pub is_daylight: bool,
205    pub precipitation_intensity: f64,
206    pub metadata: WeatherMetadata,
207}
208
209impl CurrentWeather {
210    pub(crate) fn from_owned_ptr(ptr: *mut c_void) -> Result<Self, WeatherKitError> {
211        parse_json_from_handle(
212            ptr,
213            ffi::current_weather::wk_current_weather_release,
214            ffi::current_weather::wk_current_weather_copy_json,
215            "current weather",
216        )
217    }
218
219    pub fn pressure_reading(&self) -> Pressure {
220        Pressure::new(self.pressure, self.pressure_trend.clone())
221    }
222}