1use std::ffi::c_void;
50use std::future::Future;
51use std::pin::Pin;
52use std::task::{Context, Poll};
53
54use doom_fish_utils::completion::{error_from_cstr, AsyncCompletion, AsyncCompletionFuture};
55use doom_fish_utils::panic_safe::catch_user_panic;
56
57use crate::availability_kind::WeatherAvailability;
58use crate::changes::{HistoricalComparisons, WeatherChanges};
59use crate::current_weather::CurrentWeather;
60use crate::daily_forecast::DailyForecast;
61use crate::error::WeatherKitError;
62use crate::error::ErrorPayload;
63use crate::ffi;
64use crate::hourly_forecast::HourlyForecast;
65use crate::minute_forecast::MinuteForecastCollection;
66use crate::private::parse_json_from_handle;
67use crate::service::{CLLocation, DateInterval, Weather, WeatherService};
68use crate::weather_alert::{alerts_from_owned_ptr, WeatherAlert};
69use crate::weather_attribution::WeatherAttribution;
70
71fn unix_seconds(t: std::time::SystemTime) -> f64 {
76 t.duration_since(std::time::UNIX_EPOCH)
77 .map_or(0.0, |d| d.as_secs_f64())
78}
79
80fn parse_async_error(msg: String) -> WeatherKitError {
84 serde_json::from_str::<ErrorPayload>(&msg)
85 .map_or_else(|_| WeatherKitError::bridge(-1, msg), WeatherKitError::from_payload)
86}
87
88fn acquire_service_ptr(svc: WeatherService) -> Result<*mut c_void, WeatherKitError> {
93 let ptr = unsafe {
97 if svc.is_owned() {
98 ffi::service::wk_weather_service_new()
99 } else {
100 ffi::service::wk_weather_service_shared()
101 }
102 };
103 if ptr.is_null() {
104 Err(WeatherKitError::bridge(
105 -1,
106 "failed to acquire WeatherService handle",
107 ))
108 } else {
109 Ok(ptr)
110 }
111}
112
113type RawCb = unsafe extern "C" fn(*const c_void, *const i8, *mut c_void);
119
120extern "C" fn weather_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
125 catch_user_panic("weather_cb", || {
126 if !error.is_null() {
127 let msg = unsafe { error_from_cstr(error) };
128 unsafe { AsyncCompletion::<Weather>::complete_err(ctx, msg) };
129 } else if !result.is_null() {
130 let ptr = result.cast_mut();
131 match parse_json_from_handle::<Weather>(
132 ptr,
133 ffi::service::wk_weather_release,
134 ffi::service::wk_weather_copy_json,
135 "weather",
136 ) {
137 Ok(w) => unsafe { AsyncCompletion::complete_ok(ctx, w) },
138 Err(e) => unsafe { AsyncCompletion::<Weather>::complete_err(ctx, e.to_string()) },
139 }
140 } else {
141 unsafe { AsyncCompletion::<Weather>::complete_err(ctx, "weather_cb: null result and null error".into()) };
142 }
143 });
144}
145
146pub struct WeatherFuture {
148 inner: AsyncCompletionFuture<Weather>,
149 _service_ptr: ServicePtrGuard,
150}
151
152impl Future for WeatherFuture {
153 type Output = Result<Weather, WeatherKitError>;
154
155 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
156 Pin::new(&mut self.inner)
157 .poll(cx)
158 .map(|r| r.map_err(parse_async_error))
159 }
160}
161
162extern "C" fn current_weather_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
167 catch_user_panic("current_weather_cb", || {
168 if !error.is_null() {
169 let msg = unsafe { error_from_cstr(error) };
170 unsafe { AsyncCompletion::<CurrentWeather>::complete_err(ctx, msg) };
171 } else if !result.is_null() {
172 let ptr = result.cast_mut();
173 match CurrentWeather::from_owned_ptr(ptr) {
174 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
175 Err(e) => unsafe { AsyncCompletion::<CurrentWeather>::complete_err(ctx, e.to_string()) },
176 }
177 } else {
178 unsafe { AsyncCompletion::<CurrentWeather>::complete_err(ctx, "current_weather_cb: null result and null error".into()) };
179 }
180 });
181}
182
183pub struct CurrentWeatherFuture {
185 inner: AsyncCompletionFuture<CurrentWeather>,
186 _service_ptr: ServicePtrGuard,
187}
188
189impl Future for CurrentWeatherFuture {
190 type Output = Result<CurrentWeather, WeatherKitError>;
191
192 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
193 Pin::new(&mut self.inner)
194 .poll(cx)
195 .map(|r| r.map_err(parse_async_error))
196 }
197}
198
199extern "C" fn hourly_forecast_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
204 catch_user_panic("hourly_forecast_cb", || {
205 if !error.is_null() {
206 let msg = unsafe { error_from_cstr(error) };
207 unsafe { AsyncCompletion::<HourlyForecast>::complete_err(ctx, msg) };
208 } else if !result.is_null() {
209 let ptr = result.cast_mut();
210 match HourlyForecast::from_owned_ptr(ptr) {
211 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
212 Err(e) => unsafe { AsyncCompletion::<HourlyForecast>::complete_err(ctx, e.to_string()) },
213 }
214 } else {
215 unsafe { AsyncCompletion::<HourlyForecast>::complete_err(ctx, "hourly_forecast_cb: null result and null error".into()) };
216 }
217 });
218}
219
220pub struct HourlyForecastFuture {
223 inner: AsyncCompletionFuture<HourlyForecast>,
224 _service_ptr: ServicePtrGuard,
225}
226
227impl Future for HourlyForecastFuture {
228 type Output = Result<HourlyForecast, WeatherKitError>;
229
230 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
231 Pin::new(&mut self.inner)
232 .poll(cx)
233 .map(|r| r.map_err(parse_async_error))
234 }
235}
236
237extern "C" fn daily_forecast_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
242 catch_user_panic("daily_forecast_cb", || {
243 if !error.is_null() {
244 let msg = unsafe { error_from_cstr(error) };
245 unsafe { AsyncCompletion::<DailyForecast>::complete_err(ctx, msg) };
246 } else if !result.is_null() {
247 let ptr = result.cast_mut();
248 match DailyForecast::from_owned_ptr(ptr) {
249 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
250 Err(e) => unsafe { AsyncCompletion::<DailyForecast>::complete_err(ctx, e.to_string()) },
251 }
252 } else {
253 unsafe { AsyncCompletion::<DailyForecast>::complete_err(ctx, "daily_forecast_cb: null result and null error".into()) };
254 }
255 });
256}
257
258pub struct DailyForecastFuture {
261 inner: AsyncCompletionFuture<DailyForecast>,
262 _service_ptr: ServicePtrGuard,
263}
264
265impl Future for DailyForecastFuture {
266 type Output = Result<DailyForecast, WeatherKitError>;
267
268 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
269 Pin::new(&mut self.inner)
270 .poll(cx)
271 .map(|r| r.map_err(parse_async_error))
272 }
273}
274
275extern "C" fn minute_forecast_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
280 catch_user_panic("minute_forecast_cb", || {
281 if !error.is_null() {
282 let msg = unsafe { error_from_cstr(error) };
283 unsafe { AsyncCompletion::<Option<MinuteForecastCollection>>::complete_err(ctx, msg) };
284 } else if !result.is_null() {
285 let ptr = result.cast_mut();
286 match MinuteForecastCollection::option_from_owned_ptr(ptr) {
287 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
288 Err(e) => unsafe { AsyncCompletion::<Option<MinuteForecastCollection>>::complete_err(ctx, e.to_string()) },
289 }
290 } else {
291 unsafe { AsyncCompletion::<Option<MinuteForecastCollection>>::complete_err(ctx, "minute_forecast_cb: null result and null error".into()) };
292 }
293 });
294}
295
296pub struct MinuteForecastFuture {
298 inner: AsyncCompletionFuture<Option<MinuteForecastCollection>>,
299 _service_ptr: ServicePtrGuard,
300}
301
302impl Future for MinuteForecastFuture {
303 type Output = Result<Option<MinuteForecastCollection>, WeatherKitError>;
304
305 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
306 Pin::new(&mut self.inner)
307 .poll(cx)
308 .map(|r| r.map_err(parse_async_error))
309 }
310}
311
312extern "C" fn weather_alerts_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
317 catch_user_panic("weather_alerts_cb", || {
318 if !error.is_null() {
319 let msg = unsafe { error_from_cstr(error) };
320 unsafe { AsyncCompletion::<Vec<WeatherAlert>>::complete_err(ctx, msg) };
321 } else if !result.is_null() {
322 let ptr = result.cast_mut();
323 match alerts_from_owned_ptr(ptr) {
324 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
325 Err(e) => unsafe { AsyncCompletion::<Vec<WeatherAlert>>::complete_err(ctx, e.to_string()) },
326 }
327 } else {
328 unsafe { AsyncCompletion::<Vec<WeatherAlert>>::complete_err(ctx, "weather_alerts_cb: null result and null error".into()) };
329 }
330 });
331}
332
333pub struct WeatherAlertsFuture {
335 inner: AsyncCompletionFuture<Vec<WeatherAlert>>,
336 _service_ptr: ServicePtrGuard,
337}
338
339impl Future for WeatherAlertsFuture {
340 type Output = Result<Vec<WeatherAlert>, WeatherKitError>;
341
342 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
343 Pin::new(&mut self.inner)
344 .poll(cx)
345 .map(|r| r.map_err(parse_async_error))
346 }
347}
348
349extern "C" fn availability_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
354 catch_user_panic("availability_cb", || {
355 if !error.is_null() {
356 let msg = unsafe { error_from_cstr(error) };
357 unsafe { AsyncCompletion::<WeatherAvailability>::complete_err(ctx, msg) };
358 } else if !result.is_null() {
359 let ptr = result.cast_mut();
360 match WeatherAvailability::from_owned_ptr(ptr) {
361 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
362 Err(e) => unsafe { AsyncCompletion::<WeatherAvailability>::complete_err(ctx, e.to_string()) },
363 }
364 } else {
365 unsafe { AsyncCompletion::<WeatherAvailability>::complete_err(ctx, "availability_cb: null result and null error".into()) };
366 }
367 });
368}
369
370pub struct AvailabilityFuture {
372 inner: AsyncCompletionFuture<WeatherAvailability>,
373 _service_ptr: ServicePtrGuard,
374}
375
376impl Future for AvailabilityFuture {
377 type Output = Result<WeatherAvailability, WeatherKitError>;
378
379 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
380 Pin::new(&mut self.inner)
381 .poll(cx)
382 .map(|r| r.map_err(parse_async_error))
383 }
384}
385
386extern "C" fn attribution_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
391 catch_user_panic("attribution_cb", || {
392 if !error.is_null() {
393 let msg = unsafe { error_from_cstr(error) };
394 unsafe { AsyncCompletion::<WeatherAttribution>::complete_err(ctx, msg) };
395 } else if !result.is_null() {
396 let ptr = result.cast_mut();
397 match WeatherAttribution::from_owned_ptr(ptr) {
398 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
399 Err(e) => unsafe { AsyncCompletion::<WeatherAttribution>::complete_err(ctx, e.to_string()) },
400 }
401 } else {
402 unsafe { AsyncCompletion::<WeatherAttribution>::complete_err(ctx, "attribution_cb: null result and null error".into()) };
403 }
404 });
405}
406
407pub struct AttributionFuture {
409 inner: AsyncCompletionFuture<WeatherAttribution>,
410 _service_ptr: ServicePtrGuard,
411}
412
413impl Future for AttributionFuture {
414 type Output = Result<WeatherAttribution, WeatherKitError>;
415
416 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
417 Pin::new(&mut self.inner)
418 .poll(cx)
419 .map(|r| r.map_err(parse_async_error))
420 }
421}
422
423extern "C" fn weather_changes_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
428 catch_user_panic("weather_changes_cb", || {
429 if !error.is_null() {
430 let msg = unsafe { error_from_cstr(error) };
431 unsafe { AsyncCompletion::<Option<WeatherChanges>>::complete_err(ctx, msg) };
432 } else if !result.is_null() {
433 let ptr = result.cast_mut();
434 match WeatherChanges::option_from_owned_ptr(ptr) {
435 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
436 Err(e) => unsafe { AsyncCompletion::<Option<WeatherChanges>>::complete_err(ctx, e.to_string()) },
437 }
438 } else {
439 unsafe { AsyncCompletion::<Option<WeatherChanges>>::complete_err(ctx, "weather_changes_cb: null result and null error".into()) };
440 }
441 });
442}
443
444pub struct WeatherChangesFuture {
448 inner: AsyncCompletionFuture<Option<WeatherChanges>>,
449 _service_ptr: ServicePtrGuard,
450}
451
452impl Future for WeatherChangesFuture {
453 type Output = Result<Option<WeatherChanges>, WeatherKitError>;
454
455 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
456 Pin::new(&mut self.inner)
457 .poll(cx)
458 .map(|r| r.map_err(parse_async_error))
459 }
460}
461
462extern "C" fn historical_comparisons_cb(result: *const c_void, error: *const i8, ctx: *mut c_void) {
467 catch_user_panic("historical_comparisons_cb", || {
468 if !error.is_null() {
469 let msg = unsafe { error_from_cstr(error) };
470 unsafe { AsyncCompletion::<Option<HistoricalComparisons>>::complete_err(ctx, msg) };
471 } else if !result.is_null() {
472 let ptr = result.cast_mut();
473 match HistoricalComparisons::option_from_owned_ptr(ptr) {
474 Ok(v) => unsafe { AsyncCompletion::complete_ok(ctx, v) },
475 Err(e) => unsafe { AsyncCompletion::<Option<HistoricalComparisons>>::complete_err(ctx, e.to_string()) },
476 }
477 } else {
478 unsafe { AsyncCompletion::<Option<HistoricalComparisons>>::complete_err(ctx, "historical_comparisons_cb: null result and null error".into()) };
479 }
480 });
481}
482
483pub struct HistoricalComparisonsFuture {
487 inner: AsyncCompletionFuture<Option<HistoricalComparisons>>,
488 _service_ptr: ServicePtrGuard,
489}
490
491impl Future for HistoricalComparisonsFuture {
492 type Output = Result<Option<HistoricalComparisons>, WeatherKitError>;
493
494 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
495 Pin::new(&mut self.inner)
496 .poll(cx)
497 .map(|r| r.map_err(parse_async_error))
498 }
499}
500
501struct ServicePtrGuard(*mut c_void);
506
507unsafe impl Send for ServicePtrGuard {}
511unsafe impl Sync for ServicePtrGuard {}
512
513impl Drop for ServicePtrGuard {
514 fn drop(&mut self) {
515 if !self.0.is_null() {
516 unsafe { ffi::service::wk_weather_service_release(self.0) };
517 self.0 = std::ptr::null_mut();
518 }
519 }
520}
521
522#[derive(Debug, Clone, Copy)]
551pub struct AsyncWeatherService {
552 inner: WeatherService,
553}
554
555impl AsyncWeatherService {
556 pub const fn shared() -> Self {
558 Self { inner: WeatherService::shared() }
559 }
560
561 pub const fn new() -> Self {
563 Self { inner: WeatherService::new() }
564 }
565
566 fn service_ptr(self) -> Result<*mut c_void, WeatherKitError> {
573 acquire_service_ptr(self.inner)
574 }
575
576 pub fn weather(&self, location: &CLLocation) -> WeatherFuture {
588 let ptr = match self.service_ptr() {
589 Ok(p) => p,
590 Err(e) => {
591 let (future, ctx) = AsyncCompletion::create();
592 unsafe { AsyncCompletion::<Weather>::complete_err(ctx, e.to_string()) };
593 return WeatherFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
594 }
595 };
596 let (future, ctx) = AsyncCompletion::create();
597 unsafe {
598 ffi::async_ffi::wk_weather_service_weather_async(
599 ptr,
600 location.latitude,
601 location.longitude,
602 weather_cb as RawCb,
603 ctx,
604 );
605 }
606 WeatherFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
607 }
608
609 pub fn current_weather(&self, location: &CLLocation) -> CurrentWeatherFuture {
613 let ptr = match self.service_ptr() {
614 Ok(p) => p,
615 Err(e) => {
616 let (future, ctx) = AsyncCompletion::create();
617 unsafe { AsyncCompletion::<CurrentWeather>::complete_err(ctx, e.to_string()) };
618 return CurrentWeatherFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
619 }
620 };
621 let (future, ctx) = AsyncCompletion::create();
622 unsafe {
623 ffi::async_ffi::wk_weather_service_current_weather_async(
624 ptr,
625 location.latitude,
626 location.longitude,
627 current_weather_cb as RawCb,
628 ctx,
629 );
630 }
631 CurrentWeatherFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
632 }
633
634 pub fn hourly_forecast(&self, location: &CLLocation) -> HourlyForecastFuture {
638 self.hourly_forecast_impl(location, None)
639 }
640
641 pub fn hourly_forecast_in(
645 &self,
646 location: &CLLocation,
647 interval: DateInterval,
648 ) -> HourlyForecastFuture {
649 self.hourly_forecast_impl(location, Some(interval))
650 }
651
652 fn hourly_forecast_impl(
653 &self,
654 location: &CLLocation,
655 interval: Option<DateInterval>,
656 ) -> HourlyForecastFuture {
657 let ptr = match self.service_ptr() {
658 Ok(p) => p,
659 Err(e) => {
660 let (future, ctx) = AsyncCompletion::create();
661 unsafe { AsyncCompletion::<HourlyForecast>::complete_err(ctx, e.to_string()) };
662 return HourlyForecastFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
663 }
664 };
665 let (has_range, start_s, end_s) = interval
666 .as_ref()
667 .map_or((0, 0.0, 0.0), |iv| (1_i32, unix_seconds(iv.start), unix_seconds(iv.end)));
668 let (future, ctx) = AsyncCompletion::create();
669 unsafe {
670 ffi::async_ffi::wk_weather_service_hourly_forecast_async(
671 ptr,
672 location.latitude,
673 location.longitude,
674 has_range,
675 start_s,
676 end_s,
677 hourly_forecast_cb as RawCb,
678 ctx,
679 );
680 }
681 HourlyForecastFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
682 }
683
684 pub fn daily_forecast(&self, location: &CLLocation) -> DailyForecastFuture {
688 self.daily_forecast_impl(location, None)
689 }
690
691 pub fn daily_forecast_in(
695 &self,
696 location: &CLLocation,
697 interval: DateInterval,
698 ) -> DailyForecastFuture {
699 self.daily_forecast_impl(location, Some(interval))
700 }
701
702 fn daily_forecast_impl(
703 &self,
704 location: &CLLocation,
705 interval: Option<DateInterval>,
706 ) -> DailyForecastFuture {
707 let ptr = match self.service_ptr() {
708 Ok(p) => p,
709 Err(e) => {
710 let (future, ctx) = AsyncCompletion::create();
711 unsafe { AsyncCompletion::<DailyForecast>::complete_err(ctx, e.to_string()) };
712 return DailyForecastFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
713 }
714 };
715 let (has_range, start_s, end_s) = interval
716 .as_ref()
717 .map_or((0, 0.0, 0.0), |iv| (1_i32, unix_seconds(iv.start), unix_seconds(iv.end)));
718 let (future, ctx) = AsyncCompletion::create();
719 unsafe {
720 ffi::async_ffi::wk_weather_service_daily_forecast_async(
721 ptr,
722 location.latitude,
723 location.longitude,
724 has_range,
725 start_s,
726 end_s,
727 daily_forecast_cb as RawCb,
728 ctx,
729 );
730 }
731 DailyForecastFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
732 }
733
734 pub fn minute_forecast(&self, location: &CLLocation) -> MinuteForecastFuture {
740 let ptr = match self.service_ptr() {
741 Ok(p) => p,
742 Err(e) => {
743 let (future, ctx) = AsyncCompletion::create();
744 unsafe { AsyncCompletion::<Option<MinuteForecastCollection>>::complete_err(ctx, e.to_string()) };
745 return MinuteForecastFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
746 }
747 };
748 let (future, ctx) = AsyncCompletion::create();
749 unsafe {
750 ffi::async_ffi::wk_weather_service_minute_forecast_async(
751 ptr,
752 location.latitude,
753 location.longitude,
754 minute_forecast_cb as RawCb,
755 ctx,
756 );
757 }
758 MinuteForecastFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
759 }
760
761 pub fn weather_alerts(&self, location: &CLLocation) -> WeatherAlertsFuture {
765 let ptr = match self.service_ptr() {
766 Ok(p) => p,
767 Err(e) => {
768 let (future, ctx) = AsyncCompletion::create();
769 unsafe { AsyncCompletion::<Vec<WeatherAlert>>::complete_err(ctx, e.to_string()) };
770 return WeatherAlertsFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
771 }
772 };
773 let (future, ctx) = AsyncCompletion::create();
774 unsafe {
775 ffi::async_ffi::wk_weather_service_weather_alerts_async(
776 ptr,
777 location.latitude,
778 location.longitude,
779 weather_alerts_cb as RawCb,
780 ctx,
781 );
782 }
783 WeatherAlertsFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
784 }
785
786 pub fn availability(&self, location: &CLLocation) -> AvailabilityFuture {
790 let ptr = match self.service_ptr() {
791 Ok(p) => p,
792 Err(e) => {
793 let (future, ctx) = AsyncCompletion::create();
794 unsafe { AsyncCompletion::<WeatherAvailability>::complete_err(ctx, e.to_string()) };
795 return AvailabilityFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
796 }
797 };
798 let (future, ctx) = AsyncCompletion::create();
799 unsafe {
800 ffi::async_ffi::wk_weather_service_availability_async(
801 ptr,
802 location.latitude,
803 location.longitude,
804 availability_cb as RawCb,
805 ctx,
806 );
807 }
808 AvailabilityFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
809 }
810
811 pub fn attribution(&self) -> AttributionFuture {
816 let ptr = match self.service_ptr() {
817 Ok(p) => p,
818 Err(e) => {
819 let (future, ctx) = AsyncCompletion::create();
820 unsafe { AsyncCompletion::<WeatherAttribution>::complete_err(ctx, e.to_string()) };
821 return AttributionFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
822 }
823 };
824 let (future, ctx) = AsyncCompletion::create();
825 unsafe {
826 ffi::async_ffi::wk_weather_service_attribution_async(
827 ptr,
828 attribution_cb as RawCb,
829 ctx,
830 );
831 }
832 AttributionFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
833 }
834
835 pub fn weather_changes(&self, location: &CLLocation) -> WeatherChangesFuture {
841 let ptr = match self.service_ptr() {
842 Ok(p) => p,
843 Err(e) => {
844 let (future, ctx) = AsyncCompletion::create();
845 unsafe { AsyncCompletion::<Option<WeatherChanges>>::complete_err(ctx, e.to_string()) };
846 return WeatherChangesFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
847 }
848 };
849 let (future, ctx) = AsyncCompletion::create();
850 unsafe {
851 ffi::async_ffi::wk_weather_service_weather_changes_async(
852 ptr,
853 location.latitude,
854 location.longitude,
855 weather_changes_cb as RawCb,
856 ctx,
857 );
858 }
859 WeatherChangesFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
860 }
861
862 pub fn historical_comparisons(&self, location: &CLLocation) -> HistoricalComparisonsFuture {
868 let ptr = match self.service_ptr() {
869 Ok(p) => p,
870 Err(e) => {
871 let (future, ctx) = AsyncCompletion::create();
872 unsafe { AsyncCompletion::<Option<HistoricalComparisons>>::complete_err(ctx, e.to_string()) };
873 return HistoricalComparisonsFuture { inner: future, _service_ptr: ServicePtrGuard(std::ptr::null_mut()) };
874 }
875 };
876 let (future, ctx) = AsyncCompletion::create();
877 unsafe {
878 ffi::async_ffi::wk_weather_service_historical_comparisons_async(
879 ptr,
880 location.latitude,
881 location.longitude,
882 historical_comparisons_cb as RawCb,
883 ctx,
884 );
885 }
886 HistoricalComparisonsFuture { inner: future, _service_ptr: ServicePtrGuard(ptr) }
887 }
888}
889
890impl Default for AsyncWeatherService {
891 fn default() -> Self {
892 Self::shared()
893 }
894}