Skip to main content

systemconfiguration/
dynamic_store.rs

1use std::{
2    ffi::c_void,
3    panic::AssertUnwindSafe,
4    sync::{Arc, Mutex},
5};
6
7use crate::{
8    bridge::{self, CStringArray},
9    error::Result,
10    ffi, PropertyList, SystemConfigurationError,
11};
12
13struct CallbackState {
14    callback: Box<dyn FnMut(Vec<String>) + Send>,
15}
16
17unsafe extern "C" fn dynamic_store_callback(
18    changed_keys_raw: bridge::RawHandle,
19    info: *mut c_void,
20) {
21    if info.is_null() {
22        return;
23    }
24
25    // SAFETY: `info` is `Arc::as_ptr(state).cast_mut().cast::<c_void>()` kept
26    // alive by `DynamicStore::_callback` for the entire lifetime of the store.
27    // This callback is only invoked while the store is alive.
28    let mutex = unsafe { &*info.cast::<Mutex<CallbackState>>() };
29    if let Ok(mut state) = mutex.lock() {
30        let keys = bridge::take_string_array(changed_keys_raw);
31        // Catch panics: unwinding across the Swift/C FFI boundary is UB.
32        let _ = std::panic::catch_unwind(AssertUnwindSafe(|| {
33            (state.callback)(keys);
34        }));
35    }
36}
37
38#[derive(Clone)]
39/// Wraps `SCDynamicStoreRef`.
40pub struct DynamicStore {
41    raw: bridge::OwnedHandle,
42    _callback: Option<Arc<Mutex<CallbackState>>>,
43}
44
45impl std::fmt::Debug for DynamicStore {
46    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47        f.debug_struct("DynamicStore").finish_non_exhaustive()
48    }
49}
50
51#[derive(Clone)]
52/// Wraps the `CFRunLoopSourceRef` created by `SCDynamicStoreCreateRunLoopSource`.
53pub struct DynamicStoreRunLoopSource {
54    raw: bridge::OwnedHandle,
55}
56
57impl std::fmt::Debug for DynamicStoreRunLoopSource {
58    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59        f.debug_struct("DynamicStoreRunLoopSource")
60            .finish_non_exhaustive()
61    }
62}
63
64impl DynamicStore {
65    /// Wraps `SCDynamicStoreGetTypeID`.
66    pub fn type_id() -> u64 {
67        unsafe { ffi::dynamic_store::sc_dynamic_store_get_type_id() }
68    }
69
70    /// Wraps `SCDynamicStoreCreate`.
71    pub fn new(name: &str) -> Result<Self> {
72        Self::create(name, None, false, None)
73    }
74
75    /// Wraps `SCDynamicStoreCreate` with session-key notifications enabled.
76    pub fn new_with_session_keys(name: &str) -> Result<Self> {
77        Self::create(name, None, true, None)
78    }
79
80    /// `options` must encode a dictionary accepted by `SCDynamicStoreCreateWithOptions`.
81    /// Use `new_with_session_keys` for the common session-keys configuration.
82    pub fn new_with_options(name: &str, options: &PropertyList) -> Result<Self> {
83        Self::create(name, Some(options), false, None)
84    }
85
86    /// Wraps `SCDynamicStoreCreate` with an `SCDynamicStoreCallBack`.
87    pub fn new_with_callback<F>(name: &str, callback: F) -> Result<Self>
88    where
89        F: FnMut(Vec<String>) + Send + 'static,
90    {
91        let callback = Arc::new(Mutex::new(CallbackState {
92            callback: Box::new(callback),
93        }));
94        Self::create(name, None, false, Some(callback))
95    }
96
97    /// `options` must encode a dictionary accepted by `SCDynamicStoreCreateWithOptions`.
98    /// Use `new_with_session_keys_and_callback` for the common session-keys configuration.
99    pub fn new_with_options_and_callback<F>(
100        name: &str,
101        options: &PropertyList,
102        callback: F,
103    ) -> Result<Self>
104    where
105        F: FnMut(Vec<String>) + Send + 'static,
106    {
107        let callback = Arc::new(Mutex::new(CallbackState {
108            callback: Box::new(callback),
109        }));
110        Self::create(name, Some(options), false, Some(callback))
111    }
112
113    /// Wraps `SCDynamicStoreCreate` with session-key notifications and an `SCDynamicStoreCallBack`.
114    pub fn new_with_session_keys_and_callback<F>(name: &str, callback: F) -> Result<Self>
115    where
116        F: FnMut(Vec<String>) + Send + 'static,
117    {
118        let callback = Arc::new(Mutex::new(CallbackState {
119            callback: Box::new(callback),
120        }));
121        Self::create(name, None, true, Some(callback))
122    }
123
124    fn create(
125        name: &str,
126        options: Option<&PropertyList>,
127        use_session_keys: bool,
128        callback: Option<Arc<Mutex<CallbackState>>>,
129    ) -> Result<Self> {
130        let function = match (options.is_some(), callback.is_some()) {
131            (false, false) => "sc_dynamic_store_create",
132            (false, true) => "sc_dynamic_store_create_with_callback",
133            (true, false) => "sc_dynamic_store_create_with_options",
134            (true, true) => "sc_dynamic_store_create_with_options_and_callback",
135        };
136        let name = bridge::cstring(name, function)?;
137        let raw = unsafe {
138            match (options, callback.as_ref()) {
139                (Some(options), None) => ffi::dynamic_store::sc_dynamic_store_create_with_options(
140                    name.as_ptr(),
141                    options.as_ptr(),
142                ),
143                (Some(options), Some(state)) => {
144                    ffi::dynamic_store::sc_dynamic_store_create_with_options_and_callback(
145                        name.as_ptr(),
146                        options.as_ptr(),
147                        Some(dynamic_store_callback),
148                        Arc::as_ptr(state).cast_mut().cast::<c_void>(),
149                    )
150                }
151                (None, None) => ffi::dynamic_store::sc_dynamic_store_create(
152                    name.as_ptr(),
153                    u8::from(use_session_keys),
154                ),
155                (None, Some(state)) => ffi::dynamic_store::sc_dynamic_store_create_with_callback(
156                    name.as_ptr(),
157                    u8::from(use_session_keys),
158                    Some(dynamic_store_callback),
159                    Arc::as_ptr(state).cast_mut().cast::<c_void>(),
160                ),
161            }
162        };
163        let raw = bridge::owned_handle_or_last(function, raw)?;
164        Ok(Self {
165            raw,
166            _callback: callback,
167        })
168    }
169
170    /// Wraps `SCDynamicStoreCopyValue`.
171    pub fn copy_value(&self, key: &str) -> Result<Option<PropertyList>> {
172        let key = bridge::cstring(key, "sc_dynamic_store_copy_value")?;
173        let raw = unsafe {
174            ffi::dynamic_store::sc_dynamic_store_copy_value(self.raw.as_ptr(), key.as_ptr())
175        };
176        Ok(unsafe { bridge::OwnedHandle::from_raw(raw) }.map(PropertyList::from_owned_handle))
177    }
178
179    /// Wraps `SCDynamicStoreCopyMultiple`.
180    pub fn copy_multiple<K, P>(&self, keys: &[K], patterns: &[P]) -> Result<Option<PropertyList>>
181    where
182        K: AsRef<str>,
183        P: AsRef<str>,
184    {
185        let keys = CStringArray::new(keys, "sc_dynamic_store_copy_multiple")?;
186        let patterns = CStringArray::new(patterns, "sc_dynamic_store_copy_multiple")?;
187        let raw = unsafe {
188            ffi::dynamic_store::sc_dynamic_store_copy_multiple(
189                self.raw.as_ptr(),
190                keys.as_ptr(),
191                keys.count(),
192                patterns.as_ptr(),
193                patterns.count(),
194            )
195        };
196        Ok(unsafe { bridge::OwnedHandle::from_raw(raw) }.map(PropertyList::from_owned_handle))
197    }
198
199    /// Wraps `SCDynamicStoreAddValue`.
200    pub fn add_value(&self, key: &str, value: &PropertyList) -> Result<()> {
201        let key = bridge::cstring(key, "sc_dynamic_store_add_value")?;
202        let ok = unsafe {
203            ffi::dynamic_store::sc_dynamic_store_add_value(
204                self.raw.as_ptr(),
205                key.as_ptr(),
206                value.as_ptr(),
207            )
208        };
209        bridge::bool_result("sc_dynamic_store_add_value", ok)
210    }
211
212    /// Wraps `SCDynamicStoreAddTemporaryValue`.
213    pub fn add_temporary_value(&self, key: &str, value: &PropertyList) -> Result<()> {
214        let key = bridge::cstring(key, "sc_dynamic_store_add_temporary_value")?;
215        let ok = unsafe {
216            ffi::dynamic_store::sc_dynamic_store_add_temporary_value(
217                self.raw.as_ptr(),
218                key.as_ptr(),
219                value.as_ptr(),
220            )
221        };
222        bridge::bool_result("sc_dynamic_store_add_temporary_value", ok)
223    }
224
225    /// Wraps `SCDynamicStoreSetValue`.
226    pub fn set_value(&self, key: &str, value: &PropertyList) -> Result<()> {
227        let key = bridge::cstring(key, "sc_dynamic_store_set_value")?;
228        let ok = unsafe {
229            ffi::dynamic_store::sc_dynamic_store_set_value(
230                self.raw.as_ptr(),
231                key.as_ptr(),
232                value.as_ptr(),
233            )
234        };
235        bridge::bool_result("sc_dynamic_store_set_value", ok)
236    }
237
238    /// Wraps `SCDynamicStoreSetMultiple`.
239    pub fn set_multiple<R, N>(
240        &self,
241        keys_to_set: Option<&PropertyList>,
242        keys_to_remove: &[R],
243        keys_to_notify: &[N],
244    ) -> Result<()>
245    where
246        R: AsRef<str>,
247        N: AsRef<str>,
248    {
249        let keys_to_remove = CStringArray::new(keys_to_remove, "sc_dynamic_store_set_multiple")?;
250        let keys_to_notify = CStringArray::new(keys_to_notify, "sc_dynamic_store_set_multiple")?;
251        let ok = unsafe {
252            ffi::dynamic_store::sc_dynamic_store_set_multiple(
253                self.raw.as_ptr(),
254                keys_to_set.map_or(std::ptr::null_mut(), PropertyList::as_ptr),
255                keys_to_remove.as_ptr(),
256                keys_to_remove.count(),
257                keys_to_notify.as_ptr(),
258                keys_to_notify.count(),
259            )
260        };
261        bridge::bool_result("sc_dynamic_store_set_multiple", ok)
262    }
263
264    /// Wraps `SCDynamicStoreRemoveValue`.
265    pub fn remove_value(&self, key: &str) -> Result<()> {
266        let key = bridge::cstring(key, "sc_dynamic_store_remove_value")?;
267        let ok = unsafe {
268            ffi::dynamic_store::sc_dynamic_store_remove_value(self.raw.as_ptr(), key.as_ptr())
269        };
270        bridge::bool_result("sc_dynamic_store_remove_value", ok)
271    }
272
273    /// Wraps `SCDynamicStoreNotifyValue`.
274    pub fn notify_value(&self, key: &str) -> Result<()> {
275        let key = bridge::cstring(key, "sc_dynamic_store_notify_value")?;
276        let ok = unsafe {
277            ffi::dynamic_store::sc_dynamic_store_notify_value(self.raw.as_ptr(), key.as_ptr())
278        };
279        bridge::bool_result("sc_dynamic_store_notify_value", ok)
280    }
281
282    /// Wraps `SCDynamicStoreCopyKeyList`.
283    pub fn copy_key_list(&self, pattern: &str) -> Result<Vec<String>> {
284        let pattern = bridge::cstring(pattern, "sc_dynamic_store_copy_key_list")?;
285        let raw = unsafe {
286            ffi::dynamic_store::sc_dynamic_store_copy_key_list(self.raw.as_ptr(), pattern.as_ptr())
287        };
288        Ok(bridge::take_string_array(raw))
289    }
290
291    /// Wraps `SCDynamicStoreSetNotificationKeys`.
292    pub fn set_notification_keys<K, P>(&self, keys: &[K], patterns: &[P]) -> Result<()>
293    where
294        K: AsRef<str>,
295        P: AsRef<str>,
296    {
297        let keys = CStringArray::new(keys, "sc_dynamic_store_set_notification_keys")?;
298        let patterns = CStringArray::new(patterns, "sc_dynamic_store_set_notification_keys")?;
299        let ok = unsafe {
300            ffi::dynamic_store::sc_dynamic_store_set_notification_keys(
301                self.raw.as_ptr(),
302                keys.as_ptr(),
303                keys.count(),
304                patterns.as_ptr(),
305                patterns.count(),
306            )
307        };
308        bridge::bool_result("sc_dynamic_store_set_notification_keys", ok)
309    }
310
311    /// Wraps `SCDynamicStoreCreateRunLoopSource`.
312    pub fn create_run_loop_source(&self, order: isize) -> Result<DynamicStoreRunLoopSource> {
313        let raw = unsafe {
314            ffi::dynamic_store::sc_dynamic_store_create_run_loop_source(self.raw.as_ptr(), order)
315        };
316        let raw = bridge::owned_handle_or_last("sc_dynamic_store_create_run_loop_source", raw)?;
317        Ok(DynamicStoreRunLoopSource { raw })
318    }
319
320    /// Wraps `SCDynamicStoreSetDispatchQueueGlobal`.
321    pub fn set_dispatch_queue_global(&self) -> Result<()> {
322        let ok = unsafe {
323            ffi::dynamic_store::sc_dynamic_store_set_dispatch_queue_global(self.raw.as_ptr())
324        };
325        bridge::bool_result("sc_dynamic_store_set_dispatch_queue_global", ok)
326    }
327
328    /// Wraps `SCDynamicStoreClearDispatchQueue`.
329    pub fn clear_dispatch_queue(&self) -> Result<()> {
330        let ok =
331            unsafe { ffi::dynamic_store::sc_dynamic_store_clear_dispatch_queue(self.raw.as_ptr()) };
332        bridge::bool_result("sc_dynamic_store_clear_dispatch_queue", ok)
333    }
334
335    /// Wraps `SCDynamicStoreCopyNotifiedKeys`.
336    pub fn copy_notified_keys(&self) -> Vec<String> {
337        let raw =
338            unsafe { ffi::dynamic_store::sc_dynamic_store_copy_notified_keys(self.raw.as_ptr()) };
339        bridge::take_string_array(raw)
340    }
341
342    /// Wraps `SCDynamicStoreCopyComputerName`.
343    pub fn computer_name(&self) -> Option<String> {
344        bridge::take_optional_string(unsafe {
345            ffi::dynamic_store::sc_dynamic_store_copy_computer_name(self.raw.as_ptr())
346        })
347    }
348
349    /// Wraps `SCDynamicStoreCopyLocalHostName`.
350    pub fn local_host_name(&self) -> Option<String> {
351        bridge::take_optional_string(unsafe {
352            ffi::dynamic_store::sc_dynamic_store_copy_local_host_name(self.raw.as_ptr())
353        })
354    }
355
356    /// Wraps `SCDynamicStoreCopyLocation`.
357    pub fn location(&self) -> Option<String> {
358        bridge::take_optional_string(unsafe {
359            ffi::dynamic_store::sc_dynamic_store_copy_location(self.raw.as_ptr())
360        })
361    }
362
363    /// Wraps `SCDynamicStoreCopyProxies`.
364    pub fn proxies(&self) -> Option<PropertyList> {
365        let raw = unsafe { ffi::dynamic_store::sc_dynamic_store_copy_proxies(self.raw.as_ptr()) };
366        unsafe { bridge::OwnedHandle::from_raw(raw) }.map(PropertyList::from_owned_handle)
367    }
368
369    /// Wraps `SCDynamicStoreCopyDHCPInfo`.
370    pub fn dhcp_info(&self, service_id: Option<&str>) -> Result<Option<PropertyList>> {
371        let service_id = bridge::optional_cstring(service_id, "sc_dynamic_store_copy_dhcp_info")?;
372        let raw = unsafe {
373            ffi::dynamic_store::sc_dynamic_store_copy_dhcp_info(
374                self.raw.as_ptr(),
375                service_id
376                    .as_ref()
377                    .map_or(std::ptr::null(), |value| value.as_ptr()),
378            )
379        };
380        Ok(unsafe { bridge::OwnedHandle::from_raw(raw) }.map(PropertyList::from_owned_handle))
381    }
382
383    /// Wraps `SCDHCPInfoCopyOptionData`.
384    pub fn dhcp_option_data(info: &PropertyList, code: u8) -> Option<PropertyList> {
385        unsafe {
386            bridge::OwnedHandle::from_raw(ffi::dynamic_store::sc_dhcp_info_copy_option_data(
387                info.as_ptr(),
388                code,
389            ))
390        }
391        .map(PropertyList::from_owned_handle)
392    }
393
394    /// Wraps `SCDHCPInfoCopyLeaseStartTime`.
395    pub fn dhcp_lease_start_time(info: &PropertyList) -> Option<PropertyList> {
396        unsafe {
397            bridge::OwnedHandle::from_raw(ffi::dynamic_store::sc_dhcp_info_copy_lease_start_time(
398                info.as_ptr(),
399            ))
400        }
401        .map(PropertyList::from_owned_handle)
402    }
403
404    /// Wraps `SCDHCPInfoCopyLeaseExpirationTime`.
405    pub fn dhcp_lease_expiration_time(info: &PropertyList) -> Option<PropertyList> {
406        unsafe {
407            bridge::OwnedHandle::from_raw(
408                ffi::dynamic_store::sc_dhcp_info_copy_lease_expiration_time(info.as_ptr()),
409            )
410        }
411        .map(PropertyList::from_owned_handle)
412    }
413
414    /// Wraps `SCDynamicStoreKeyCreate`.
415    pub fn key_create<A: AsRef<str>>(format: &str, arguments: &[A]) -> Result<String> {
416        let format = bridge::cstring(format, "sc_dynamic_store_key_create")?;
417        let arguments = CStringArray::new(arguments, "sc_dynamic_store_key_create")?;
418        bridge::take_optional_string(unsafe {
419            ffi::dynamic_store::sc_dynamic_store_key_create(
420                format.as_ptr(),
421                arguments.as_ptr(),
422                arguments.count(),
423            )
424        })
425        .ok_or_else(|| {
426            SystemConfigurationError::null(
427                "sc_dynamic_store_key_create",
428                "bridge returned null dynamic-store formatted key",
429            )
430        })
431    }
432
433    /// Wraps `SCDynamicStoreKeyCreateNetworkGlobalEntity`.
434    pub fn network_global_entity_key(domain: &str, entity: &str) -> Result<String> {
435        let domain = bridge::cstring(domain, "sc_dynamic_store_key_create_network_global_entity")?;
436        let entity = bridge::cstring(entity, "sc_dynamic_store_key_create_network_global_entity")?;
437        bridge::take_optional_string(unsafe {
438            ffi::dynamic_store::sc_dynamic_store_key_create_network_global_entity(
439                domain.as_ptr(),
440                entity.as_ptr(),
441            )
442        })
443        .ok_or_else(|| {
444            SystemConfigurationError::null(
445                "sc_dynamic_store_key_create_network_global_entity",
446                "bridge returned null dynamic-store global entity key",
447            )
448        })
449    }
450
451    /// Wraps `SCDynamicStoreKeyCreateNetworkInterface`.
452    pub fn network_interface_key(domain: &str) -> Result<String> {
453        let domain = bridge::cstring(domain, "sc_dynamic_store_key_create_network_interface")?;
454        bridge::take_optional_string(unsafe {
455            ffi::dynamic_store::sc_dynamic_store_key_create_network_interface(domain.as_ptr())
456        })
457        .ok_or_else(|| {
458            SystemConfigurationError::null(
459                "sc_dynamic_store_key_create_network_interface",
460                "bridge returned null dynamic-store interface key",
461            )
462        })
463    }
464
465    /// Wraps `SCDynamicStoreKeyCreateNetworkInterfaceEntity`.
466    pub fn network_interface_entity_key(
467        domain: &str,
468        interface_name: &str,
469        entity: Option<&str>,
470    ) -> Result<String> {
471        let domain = bridge::cstring(
472            domain,
473            "sc_dynamic_store_key_create_network_interface_entity",
474        )?;
475        let interface_name = bridge::cstring(
476            interface_name,
477            "sc_dynamic_store_key_create_network_interface_entity",
478        )?;
479        let entity = bridge::optional_cstring(
480            entity,
481            "sc_dynamic_store_key_create_network_interface_entity",
482        )?;
483        bridge::take_optional_string(unsafe {
484            ffi::dynamic_store::sc_dynamic_store_key_create_network_interface_entity(
485                domain.as_ptr(),
486                interface_name.as_ptr(),
487                entity
488                    .as_ref()
489                    .map_or(std::ptr::null(), |value| value.as_ptr()),
490            )
491        })
492        .ok_or_else(|| {
493            SystemConfigurationError::null(
494                "sc_dynamic_store_key_create_network_interface_entity",
495                "bridge returned null dynamic-store interface-entity key",
496            )
497        })
498    }
499
500    /// Wraps `SCDynamicStoreKeyCreateNetworkServiceEntity`.
501    pub fn network_service_entity_key(
502        domain: &str,
503        service_id: &str,
504        entity: Option<&str>,
505    ) -> Result<String> {
506        let domain = bridge::cstring(domain, "sc_dynamic_store_key_create_network_service_entity")?;
507        let service_id = bridge::cstring(
508            service_id,
509            "sc_dynamic_store_key_create_network_service_entity",
510        )?;
511        let entity =
512            bridge::optional_cstring(entity, "sc_dynamic_store_key_create_network_service_entity")?;
513        bridge::take_optional_string(unsafe {
514            ffi::dynamic_store::sc_dynamic_store_key_create_network_service_entity(
515                domain.as_ptr(),
516                service_id.as_ptr(),
517                entity
518                    .as_ref()
519                    .map_or(std::ptr::null(), |value| value.as_ptr()),
520            )
521        })
522        .ok_or_else(|| {
523            SystemConfigurationError::null(
524                "sc_dynamic_store_key_create_network_service_entity",
525                "bridge returned null dynamic-store service-entity key",
526            )
527        })
528    }
529
530    /// Wraps `SCDynamicStoreKeyCreateComputerName`.
531    pub fn computer_name_key() -> Result<String> {
532        bridge::take_optional_string(unsafe {
533            ffi::dynamic_store::sc_dynamic_store_key_create_computer_name()
534        })
535        .ok_or_else(|| {
536            SystemConfigurationError::null(
537                "sc_dynamic_store_key_create_computer_name",
538                "bridge returned null computer-name notification key",
539            )
540        })
541    }
542
543    /// Wraps `SCDynamicStoreKeyCreateConsoleUser`.
544    pub fn console_user_key() -> Result<String> {
545        bridge::take_optional_string(unsafe {
546            ffi::dynamic_store::sc_dynamic_store_key_create_console_user()
547        })
548        .ok_or_else(|| {
549            SystemConfigurationError::null(
550                "sc_dynamic_store_key_create_console_user",
551                "bridge returned null console-user notification key",
552            )
553        })
554    }
555
556    /// Wraps `SCDynamicStoreKeyCreateHostNames`.
557    pub fn host_names_key() -> Result<String> {
558        bridge::take_optional_string(unsafe {
559            ffi::dynamic_store::sc_dynamic_store_key_create_host_names()
560        })
561        .ok_or_else(|| {
562            SystemConfigurationError::null(
563                "sc_dynamic_store_key_create_host_names",
564                "bridge returned null host-names notification key",
565            )
566        })
567    }
568
569    /// Wraps `SCDynamicStoreKeyCreateLocation`.
570    pub fn location_key() -> Result<String> {
571        bridge::take_optional_string(unsafe {
572            ffi::dynamic_store::sc_dynamic_store_key_create_location()
573        })
574        .ok_or_else(|| {
575            SystemConfigurationError::null(
576                "sc_dynamic_store_key_create_location",
577                "bridge returned null location notification key",
578            )
579        })
580    }
581
582    /// Wraps `SCDynamicStoreKeyCreateProxies`.
583    pub fn proxies_key() -> Result<String> {
584        bridge::take_optional_string(unsafe {
585            ffi::dynamic_store::sc_dynamic_store_key_create_proxies()
586        })
587        .ok_or_else(|| {
588            SystemConfigurationError::null(
589                "sc_dynamic_store_key_create_proxies",
590                "bridge returned null proxies notification key",
591            )
592        })
593    }
594}
595
596impl DynamicStoreRunLoopSource {
597    /// Wraps `SCRunLoopSourceScheduleCurrentDefaultMode`.
598    pub fn schedule_current_default_mode(&self) -> Result<()> {
599        let ok = unsafe {
600            ffi::dynamic_store::sc_run_loop_source_schedule_current_default_mode(self.raw.as_ptr())
601        };
602        bridge::bool_result("sc_run_loop_source_schedule_current_default_mode", ok)
603    }
604
605    /// Wraps `SCRunLoopSourceUnscheduleCurrentDefaultMode`.
606    pub fn unschedule_current_default_mode(&self) -> Result<()> {
607        let ok = unsafe {
608            ffi::dynamic_store::sc_run_loop_source_unschedule_current_default_mode(
609                self.raw.as_ptr(),
610            )
611        };
612        bridge::bool_result("sc_run_loop_source_unschedule_current_default_mode", ok)
613    }
614}