sabi/tokio/data_src/
global_setup.rs1use super::DataSrcError;
6
7use super::super::{
8 AutoShutdown, DataConn, DataConnContainer, DataSrc, DataSrcContainer, DataSrcManager,
9 StaticDataSrcContainer, StaticDataSrcRegistration,
10};
11use crate::SendSyncNonNull;
12
13use setup_read_cleanup::{PhasedCellAsync, PhasedError, PhasedErrorKind};
14
15use std::collections::HashMap;
16use std::sync::Arc;
17use std::{any, ptr};
18use tokio::sync::Mutex;
19
20pub(crate) static DS_MANAGER: PhasedCellAsync<DataSrcManager> =
21 PhasedCellAsync::new(DataSrcManager::new(false));
22
23const NOOP: fn(&mut DataSrcManager) -> Result<(), PhasedError> = |_| Ok(());
24
25impl Drop for AutoShutdown {
26 fn drop(&mut self) {
27 let _ = DS_MANAGER.force_to_cleanup(|ds_m| {
28 ds_m.close();
29 Ok::<(), PhasedError>(())
30 });
31 }
32}
33
34pub async fn uses_async<S, C>(name: impl Into<Arc<str>>, ds: S) -> errs::Result<()>
58where
59 S: DataSrc<C> + 'static,
60 C: DataConn + 'static,
61{
62 match DS_MANAGER.lock_async().await {
63 Ok(mut dsm) => {
64 dsm.add(name, ds);
65 Ok(())
66 }
67 Err(e) => Err(errs::Err::with_source(
68 DataSrcError::FailToRegisterGlobalDataSrc { name: name.into() },
69 e,
70 )),
71 }
72}
73
74pub fn uses<S, C>(name: impl Into<Arc<str>>, ds: S) -> errs::Result<()>
99where
100 S: DataSrc<C> + 'static,
101 C: DataConn + 'static,
102{
103 match DS_MANAGER.try_lock() {
104 Ok(mut dsm) => {
105 dsm.add(name, ds);
106 Ok(())
107 }
108 Err(e) => Err(errs::Err::with_source(
109 DataSrcError::FailToRegisterGlobalDataSrc { name: name.into() },
110 e,
111 )),
112 }
113}
114
115fn collect_static_data_src_containers(dsm: &mut DataSrcManager) {
116 let regs: Vec<_> = inventory::iter::<StaticDataSrcRegistration>
117 .into_iter()
118 .collect();
119
120 let mut static_vec: Vec<SendSyncNonNull<DataSrcContainer>> = Vec::with_capacity(regs.len());
121 for reg in regs {
122 let any_container = (reg.factory)();
123 static_vec.push(any_container.ssnnptr);
124 }
125
126 dsm.prepend(static_vec);
127}
128
129pub async fn setup_async() -> errs::Result<AutoShutdown> {
142 let errors = Arc::new(Mutex::new(Vec::new()));
143 let errors_for_closure = Arc::clone(&errors);
144
145 if let Err(e) = DS_MANAGER
146 .transition_to_read_async(move |ds_m| {
147 collect_static_data_src_containers(ds_m);
148 let errors_for_future = Arc::clone(&errors_for_closure);
149 Box::pin(async move {
150 let mut lock = errors_for_future.lock().await;
151 ds_m.setup_async(&mut lock).await;
152 Ok::<(), PhasedError>(())
153 })
154 })
155 .await
156 {
157 if e.kind() == PhasedErrorKind::DuringTransitionToRead {
158 return Err(errs::Err::new(DataSrcError::DuringSetupGlobalDataSrcs));
159 } else {
160 return Err(errs::Err::new(DataSrcError::AlreadySetupGlobalDataSrcs));
161 }
162 }
163
164 let errors = Arc::try_unwrap(errors).unwrap().into_inner();
165 if errors.is_empty() {
166 Ok(AutoShutdown {})
167 } else {
168 Err(errs::Err::new(DataSrcError::FailToSetupGlobalDataSrcs {
169 errors,
170 }))
171 }
172}
173
174pub async fn setup_with_order_async(names: &'static [&str]) -> errs::Result<AutoShutdown> {
192 let errors = Arc::new(Mutex::new(Vec::new()));
193 let errors_for_closure = Arc::clone(&errors);
194
195 if let Err(e) = DS_MANAGER
196 .transition_to_read_async(move |ds_m| {
197 collect_static_data_src_containers(ds_m);
198 let errors_for_future = Arc::clone(&errors_for_closure);
199 Box::pin(async move {
200 let mut lock = errors_for_future.lock().await;
201 ds_m.setup_with_order_async(names, &mut lock).await;
202 Ok::<(), PhasedError>(())
203 })
204 })
205 .await
206 {
207 if e.kind() == PhasedErrorKind::DuringTransitionToRead {
208 return Err(errs::Err::new(DataSrcError::DuringSetupGlobalDataSrcs));
209 } else {
210 return Err(errs::Err::new(DataSrcError::AlreadySetupGlobalDataSrcs));
211 }
212 }
213
214 let errors = Arc::try_unwrap(errors).unwrap().into_inner();
215 if errors.is_empty() {
216 Ok(AutoShutdown {})
217 } else {
218 Err(errs::Err::new(DataSrcError::FailToSetupGlobalDataSrcs {
219 errors,
220 }))
221 }
222}
223
224pub(crate) fn copy_global_data_srcs_to_map(index_map: &mut HashMap<Arc<str>, (bool, usize)>) {
225 if let Ok(ds_m) = DS_MANAGER.read_relaxed() {
226 ds_m.copy_ds_ready_to_map(index_map);
227 } else if (match DS_MANAGER.force_to_read(NOOP) {
228 Ok(_) => Ok(()),
229 Err(e) => match e.kind() {
230 PhasedErrorKind::PhaseIsAlreadyCleanup => Ok(()),
231 PhasedErrorKind::DuringTransitionToRead => Ok(()),
232 _ => Err(()),
233 },
234 })
235 .is_ok()
236 {
237 if let Ok(ds_m) = DS_MANAGER.read_relaxed() {
238 ds_m.copy_ds_ready_to_map(index_map);
239 }
240 }
241}
242
243#[doc(hidden)]
244pub fn create_static_data_src_container<S, C>(
245 name: &'static str,
246 data_src: S,
247) -> StaticDataSrcContainer
248where
249 S: DataSrc<C> + 'static,
250 C: DataConn + 'static,
251{
252 let boxed = Box::new(DataSrcContainer::<S, C>::new(name, data_src, false));
253 let ptr = ptr::NonNull::from(Box::leak(boxed)).cast::<DataSrcContainer>();
254 StaticDataSrcContainer {
255 ssnnptr: SendSyncNonNull::new(ptr),
256 }
257}
258
259impl StaticDataSrcRegistration {
260 pub const fn new(factory: fn() -> StaticDataSrcContainer) -> Self {
261 Self { factory }
262 }
263}
264inventory::collect!(StaticDataSrcRegistration);
265
266#[macro_export]
267#[doc(hidden)]
268macro_rules! _uses_for_async {
269 ($name:tt, $data_src:expr) => {
270 const _: () = {
271 inventory::submit! {
272 $crate::tokio::StaticDataSrcRegistration::new(|| {
273 $crate::tokio::create_static_data_src_container($name, $data_src)
274 })
275 }
276 };
277 };
278}
279
280pub(crate) async fn create_data_conn_from_global_data_src_async<C>(
281 index: usize,
282 name: impl AsRef<str>,
283) -> errs::Result<Box<DataConnContainer>>
284where
285 C: DataConn + 'static,
286{
287 match DS_MANAGER.read_relaxed() {
288 Ok(ds_manager) => ds_manager.create_data_conn_async::<C>(index, name).await,
289 Err(e) => Err(errs::Err::with_source(
290 DataSrcError::FailToCreateDataConn {
291 name: name.as_ref().into(),
292 data_conn_type: any::type_name::<C>(),
293 },
294 e,
295 )),
296 }
297}