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}