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.
45use super::*;
6use std::cell::{Cell, RefCell};
7use std::task::Waker;
89/// 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 {
13pub waker: Cell<Waker>,
14pub platform: RefCell<std::boxed::Box<dyn Platform>>,
15pub state_change_fn: Cell<Option<std::boxed::Box<dyn FnMut(ot::ChangedFlags)>>>,
16pub cli_output_fn: Cell<Option<std::boxed::Box<dyn FnMut(&CStr)>>>,
17pub ip6_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
18pub ip6_address_fn: Cell<Option<std::boxed::Box<dyn FnMut(Ip6AddressInfo<'_>, bool)>>>,
19pub multicast_listener_callback:
20 Cell<Option<std::boxed::Box<dyn FnMut(BackboneRouterMulticastListenerEvent, &Ip6Address)>>>,
21pub active_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&ActiveScanResult>)>>>,
22pub energy_scan_fn: Cell<Option<std::boxed::Box<dyn FnMut(Option<&EnergyScanResult>)>>>,
23pub joiner_fn: Cell<Option<std::boxed::Box<dyn FnOnce(Result)>>>,
24pub srp_server_service_update_fn: Cell<
25Option<std::boxed::Box<dyn FnMut(ot::SrpServerServiceUpdateId, &ot::SrpServerHost, u32)>>,
26 >,
27pub dnssd_query_sub_unsub_fn: Cell<Option<std::boxed::Box<dyn FnMut(bool, &CStr)>>>,
28pub nat64_receive_fn: Cell<Option<std::boxed::Box<dyn FnMut(OtMessageBox<'_>)>>>,
29pub dhcp6pd_state_change_callback_fn:
30 Cell<Option<std::boxed::Box<dyn FnMut(BorderRoutingDhcp6PdState)>>>,
31}
3233impl InstanceBacking {
34pub(crate) fn new<T: Platform + 'static>(platform: T) -> Self {
35Self {
36 waker: Cell::new(futures::task::noop_waker()),
37 platform: RefCell::new(Box::new(platform) as std::boxed::Box<dyn Platform>),
38 cli_output_fn: Cell::new(None),
39 ip6_receive_fn: Cell::new(None),
40 ip6_address_fn: Cell::new(None),
41 state_change_fn: Cell::new(None),
42 active_scan_fn: Cell::new(None),
43 energy_scan_fn: Cell::new(None),
44 joiner_fn: Cell::new(None),
45 srp_server_service_update_fn: Cell::new(None),
46 dnssd_query_sub_unsub_fn: Cell::new(None),
47 multicast_listener_callback: Cell::new(None),
48 nat64_receive_fn: Cell::new(None),
49 dhcp6pd_state_change_callback_fn: Cell::new(None),
50 }
51 }
52}
5354impl InstanceBacking {
55unsafe fn glob() -> &'static mut Option<InstanceBacking> {
56static mut SINGLETON_BACKING: Option<InstanceBacking> = None;
57// TODO(b/319328255) -- Fix usage so lint no longer applies
58#[allow(static_mut_refs)]
59&mut SINGLETON_BACKING
60 }
6162/// Returns a reference to the global singleton `InstanceBacking`.
63 ///
64 /// If you are tempted to use this method, consider using `Instance::borrow_backing()`
65 /// instead.
66 ///
67 /// ## Safety ##
68 ///
69 /// The behavior of this method is undefined when called at the same
70 /// time that `InstanceBacking::set_singleton()`/`InstanceBacking::drop_singleton()`
71 /// is being called from a different thread.
72 ///
73 /// In order to keep things safe and straightforward, this method should
74 /// only be called by the implementation of `Instance::borrow_backing()`.
75pub(crate) unsafe fn as_ref() -> &'static InstanceBacking {
76Self::glob().as_ref().expect("otInstance is uninitialized")
77 }
7879/// Initializes the singleton instance backing with the given value.
80 /// Will panic if this is called twice without calling
81 /// `InstanceBacking::finalize` in between.
82 ///
83 /// ## Safety ##
84 ///
85 /// The behavior of this method is undefined when called at the same
86 /// time that `InstanceBacking::as_ref()`/`InstanceBacking::drop_singleton()`
87 /// is being called from a different thread.
88 ///
89 /// In order to keep things safe and straightforward, this method should
90 /// only be called by the implementation of `Instance::new()`.
91pub(crate) unsafe fn set_singleton(backing: InstanceBacking) {
92trace!("Setting Singleton InstanceBacking");
93assert!(Self::glob().replace(backing).is_none(), "Tried to make two OpenThread instances");
94 }
9596/// Finalizes and drops the singleton instance backing. After this
97 /// method is called, [`InstacnceBacking::set`] may be called again.
98 ///
99 /// ## Safety ##
100 ///
101 /// The behavior of this method is undefined when called at the same
102 /// time that `InstanceBacking::set_singleton()`/`InstanceBacking::as_ref()`
103 /// is being called from a different thread.
104 ///
105 /// In order to keep things safe and straightforward, this method should
106 /// only be called by the implementation of `Instance::finalize()`.
107pub(crate) unsafe fn drop_singleton() {
108trace!("Dropping Singleton InstanceBacking");
109assert!(Self::glob().take().is_some(), "Tried to drop singleton that was never allocated");
110 }
111}