openthread/ot/singleton/
backing.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::*;
6use std::cell::{Cell, RefCell};
7use std::task::Waker;
8
9/// Backing struct for OpenThread instances. This type contains information
10/// related to the rust API implementation.
11#[allow(clippy::type_complexity)]
12pub(crate) struct InstanceBacking {
13    pub waker: Cell<Waker>,
14    pub platform: RefCell<std::boxed::Box<dyn Platform>>,
15    pub state_change_fn: Cell<Option<std::boxed::Box<dyn FnMut(ot::ChangedFlags)>>>,
16    pub cli_output_fn: Cell<Option<std::boxed::Box<dyn FnMut(&CStr)>>>,
17    pub ip6_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
18    pub ip6_address_fn: Cell<Option<std::boxed::Box<dyn FnMut(Ip6AddressInfo<'_>, bool)>>>,
19    pub multicast_listener_callback:
20        Cell<Option<std::boxed::Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address)>>>,
21    pub active_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&ActiveScanResult>)>>>,
22    pub energy_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&EnergyScanResult>)>>>,
23    pub joiner_fn: Cell<Option<std::boxed::Box<dyn FnOnce(Result)>>>,
24    pub srp_server_service_update_fn: Cell<
25        Option<std::boxed::Box<dyn FnMut(ot::SrpServerServiceUpdateId, &ot::SrpServerHost, u32)>>,
26    >,
27    pub dnssd_query_sub_unsub_fn: Cell<Option<std::boxed::Box<dyn FnMut(bool, &CStr)>>>,
28    pub nat64_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
29    pub dhcp6pd_state_change_callback_fn:
30        Cell<Option<std::boxed::Box<dyn FnMut(BorderRoutingDhcp6PdState)>>>,
31    pub ephemeral_key_callback: Cell<Option<std::boxed::Box<dyn FnMut()>>>,
32    pub meshcop_service_changed_callback: Cell<Option<std::boxed::Box<dyn FnMut()>>>,
33}
34
35impl InstanceBacking {
36    pub(crate) fn new<T: Platform + 'static>(platform: T) -> Self {
37        Self {
38            waker: Cell::new(futures::task::noop_waker()),
39            platform: RefCell::new(Box::new(platform) as std::boxed::Box<dyn Platform>),
40            cli_output_fn: Cell::new(None),
41            ip6_receive_fn: Cell::new(None),
42            ip6_address_fn: Cell::new(None),
43            state_change_fn: Cell::new(None),
44            active_scan_fn: Cell::new(None),
45            energy_scan_fn: Cell::new(None),
46            joiner_fn: Cell::new(None),
47            srp_server_service_update_fn: Cell::new(None),
48            dnssd_query_sub_unsub_fn: Cell::new(None),
49            multicast_listener_callback: Cell::new(None),
50            nat64_receive_fn: Cell::new(None),
51            dhcp6pd_state_change_callback_fn: Cell::new(None),
52            ephemeral_key_callback: Cell::new(None),
53            meshcop_service_changed_callback: Cell::new(None),
54        }
55    }
56}
57
58impl InstanceBacking {
59    unsafe fn glob() -> &'static mut Option<InstanceBacking> {
60        static mut SINGLETON_BACKING: Option<InstanceBacking> = None;
61        // TODO(b/319328255) -- Fix usage so lint no longer applies
62        #[allow(static_mut_refs)]
63        unsafe {
64            &mut SINGLETON_BACKING
65        }
66    }
67
68    /// Returns a reference to the global singleton `InstanceBacking`.
69    ///
70    /// If you are tempted to use this method, consider using `Instance::borrow_backing()`
71    /// instead.
72    ///
73    /// ## Safety ##
74    ///
75    /// The behavior of this method is undefined when called at the same
76    /// time that `InstanceBacking::set_singleton()`/`InstanceBacking::drop_singleton()`
77    /// is being called from a different thread.
78    ///
79    /// In order to keep things safe and straightforward, this method should
80    /// only be called by the implementation of `Instance::borrow_backing()`.
81    pub(crate) unsafe fn as_ref() -> &'static InstanceBacking {
82        unsafe { Self::glob() }.as_ref().expect("otInstance is uninitialized")
83    }
84
85    /// Initializes the singleton instance backing with the given value.
86    /// Will panic if this is called twice without calling
87    /// `InstanceBacking::finalize` in between.
88    ///
89    /// ## Safety ##
90    ///
91    /// The behavior of this method is undefined when called at the same
92    /// time that `InstanceBacking::as_ref()`/`InstanceBacking::drop_singleton()`
93    /// is being called from a different thread.
94    ///
95    /// In order to keep things safe and straightforward, this method should
96    /// only be called by the implementation of `Instance::new()`.
97    pub(crate) unsafe fn set_singleton(backing: InstanceBacking) {
98        trace!("Setting Singleton InstanceBacking");
99        assert!(
100            unsafe { Self::glob() }.replace(backing).is_none(),
101            "Tried to make two OpenThread instances"
102        );
103    }
104
105    /// Finalizes and drops the singleton instance backing. After this
106    /// method is called, [`InstacnceBacking::set`] may be called again.
107    ///
108    /// ## Safety ##
109    ///
110    /// The behavior of this method is undefined when called at the same
111    /// time that `InstanceBacking::set_singleton()`/`InstanceBacking::as_ref()`
112    /// is being called from a different thread.
113    ///
114    /// In order to keep things safe and straightforward, this method should
115    /// only be called by the implementation of `Instance::finalize()`.
116    pub(crate) unsafe fn drop_singleton() {
117        trace!("Dropping Singleton InstanceBacking");
118        assert!(
119            unsafe { Self::glob() }.take().is_some(),
120            "Tried to drop singleton that was never allocated"
121        );
122    }
123}