sz_rust_sdk/core/
environment.rs1use crate::{
4 error::{SzError, SzResult},
5 ffi_call, ffi_call_i64,
6 traits::*,
7 types::*,
8};
9use std::sync::atomic::{AtomicBool, Ordering};
10use std::sync::{Arc, Mutex, OnceLock};
11
12pub struct SzEnvironmentCore {
17 is_destroyed: Arc<AtomicBool>,
18 is_initialized: Arc<AtomicBool>,
19 module_name: String,
20 ini_params: String,
21 verbose_logging: bool,
22}
23
24static GLOBAL_ENVIRONMENT: OnceLock<Mutex<Option<Arc<SzEnvironmentCore>>>> = OnceLock::new();
26
27impl SzEnvironmentCore {
28 pub fn new(module_name: &str, ini_params: &str, verbose_logging: bool) -> SzResult<Self> {
36 Ok(Self {
37 is_destroyed: Arc::new(AtomicBool::new(false)),
38 is_initialized: Arc::new(AtomicBool::new(false)),
39 module_name: module_name.to_string(),
40 ini_params: ini_params.to_string(),
41 verbose_logging,
42 })
43 }
44
45 pub fn new_default() -> SzResult<Self> {
47 Self::new("SzRustSDK", "{}", false)
48 }
49
50 pub fn get_instance(
61 module_name: &str,
62 ini_params: &str,
63 verbose_logging: bool,
64 ) -> SzResult<Arc<Self>> {
65 let global_env = GLOBAL_ENVIRONMENT.get_or_init(|| Mutex::new(None));
66 let mut env_guard = global_env.lock().unwrap();
67
68 match env_guard.as_ref() {
69 Some(existing_env) => {
70 if existing_env.is_destroyed() {
72 let new_env = Arc::new(Self::new(module_name, ini_params, verbose_logging)?);
73 *env_guard = Some(new_env.clone());
74 Ok(new_env)
75 } else {
76 if existing_env.ini_params != ini_params
79 || existing_env.verbose_logging != verbose_logging
80 {
81 return Err(SzError::configuration(
82 "Cannot change critical initialization parameters (ini_params, verbose_logging) after SzEnvironmentCore instance is created",
83 ));
84 }
85 Ok(existing_env.clone())
87 }
88 }
89 None => {
90 let new_env = Arc::new(Self::new(module_name, ini_params, verbose_logging)?);
92 *env_guard = Some(new_env.clone());
93 Ok(new_env)
94 }
95 }
96 }
97
98 pub fn get_existing_instance() -> SzResult<Arc<Self>> {
107 let global_env = GLOBAL_ENVIRONMENT.get_or_init(|| Mutex::new(None));
108 let env_guard = global_env.lock().unwrap();
109
110 match env_guard.as_ref() {
111 Some(existing_env) => {
112 if existing_env.is_destroyed() {
113 Err(SzError::unrecoverable(
114 "SzEnvironmentCore instance has been destroyed",
115 ))
116 } else {
117 Ok(existing_env.clone())
118 }
119 }
120 None => Err(SzError::unrecoverable(
121 "No SzEnvironmentCore instance has been created yet. Call get_instance() first.",
122 )),
123 }
124 }
125
126 pub fn try_get_instance() -> Option<Arc<Self>> {
130 GLOBAL_ENVIRONMENT
131 .get()?
132 .lock()
133 .unwrap()
134 .as_ref()
135 .map(|env| env.clone())
136 }
137
138 pub fn destroy_global_instance() -> SzResult<()> {
142 if let Some(global_env) = GLOBAL_ENVIRONMENT.get() {
143 let mut env_guard = match global_env.lock() {
144 Ok(guard) => guard,
145 Err(poisoned) => {
146 poisoned.into_inner()
148 }
149 };
150 if let Some(env) = env_guard.take() {
151 if !env.is_destroyed() {
153 env.is_destroyed
155 .store(true, std::sync::atomic::Ordering::Relaxed);
156
157 unsafe {
160 let _ = crate::ffi::bindings::SzDiagnostic_destroy();
162 let _ = crate::ffi::bindings::SzProduct_destroy();
163 let _ = crate::ffi::bindings::Sz_destroy();
165
166 crate::ffi::bindings::Sz_clearLastException();
168 crate::ffi::bindings::SzDiagnostic_clearLastException();
169 crate::ffi::bindings::SzProduct_clearLastException();
170 }
171
172 std::thread::sleep(std::time::Duration::from_millis(100));
174 }
175 }
176 }
177 Ok(())
178 }
179
180 pub fn get_ini_params(&self) -> &str {
182 &self.ini_params
183 }
184
185 pub fn get_verbose_logging(&self) -> bool {
187 self.verbose_logging
188 }
189
190 fn ensure_initialized(&self) -> SzResult<()> {
194 if self.is_initialized.load(Ordering::Relaxed) {
195 return Ok(());
196 }
197
198 if self
200 .is_initialized
201 .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed)
202 .is_ok()
203 {
204 let module_name_c = crate::ffi::helpers::str_to_c_string(&self.module_name)?;
205 let ini_params_c = crate::ffi::helpers::str_to_c_string(&self.ini_params)?;
206 let verbose = if self.verbose_logging { 1 } else { 0 };
207
208 ffi_call!(crate::ffi::bindings::Sz_init(
209 module_name_c.as_ptr(),
210 ini_params_c.as_ptr(),
211 verbose as i64
212 ));
213 }
214
215 Ok(())
216 }
217}
218
219impl SzEnvironment for SzEnvironmentCore {
220 fn destroy(&mut self) -> SzResult<()> {
221 if self.is_destroyed.load(Ordering::Relaxed) {
222 return Ok(());
223 }
224
225 ffi_call_i64!(crate::ffi::bindings::Sz_destroy());
226 self.is_destroyed.store(true, Ordering::Relaxed);
227 Ok(())
228 }
229
230 fn is_destroyed(&self) -> bool {
231 self.is_destroyed.load(Ordering::Relaxed)
232 }
233
234 fn reinitialize(&self, config_id: ConfigId) -> SzResult<()> {
235 if self.is_destroyed() {
236 return Err(SzError::unrecoverable("Environment has been destroyed"));
237 }
238
239 self.ensure_initialized()?;
241
242 ffi_call!(crate::ffi::bindings::Sz_reinit(config_id));
243 Ok(())
244 }
245
246 fn get_active_config_id(&self) -> SzResult<ConfigId> {
247 if self.is_destroyed() {
248 return Err(SzError::unrecoverable("Environment has been destroyed"));
249 }
250
251 self.ensure_initialized()?;
253
254 let config_id = unsafe { crate::ffi::bindings::Sz_getActiveConfigID() };
255 Ok(config_id)
256 }
257
258 fn get_product(&self) -> SzResult<Box<dyn SzProduct>> {
259 if self.is_destroyed() {
260 return Err(SzError::unrecoverable("Environment has been destroyed"));
261 }
262
263 let product_core = super::product::SzProductCore::new_with_params(
265 &self.module_name,
266 &self.ini_params,
267 self.verbose_logging,
268 )?;
269 Ok(Box::new(product_core))
270 }
271
272 fn get_engine(&self) -> SzResult<Box<dyn SzEngine>> {
273 if self.is_destroyed() {
274 return Err(SzError::unrecoverable("Environment has been destroyed"));
275 }
276
277 self.ensure_initialized()?;
279
280 let engine_core = super::engine::SzEngineCore::new()?;
281 Ok(Box::new(engine_core))
282 }
283
284 fn get_config_manager(&self) -> SzResult<Box<dyn SzConfigManager>> {
285 if self.is_destroyed() {
286 return Err(SzError::unrecoverable("Environment has been destroyed"));
287 }
288
289 self.ensure_initialized()?;
291
292 let config_mgr_core = super::config_manager::SzConfigManagerCore::new()?;
293 Ok(Box::new(config_mgr_core))
294 }
295
296 fn get_diagnostic(&self) -> SzResult<Box<dyn SzDiagnostic>> {
297 if self.is_destroyed() {
298 return Err(SzError::unrecoverable("Environment has been destroyed"));
299 }
300
301 self.ensure_initialized()?;
303
304 let diagnostic_core = super::diagnostic::SzDiagnosticCore::new_with_params(
305 &self.module_name,
306 &self.ini_params,
307 self.verbose_logging,
308 )?;
309 Ok(Box::new(diagnostic_core))
310 }
311}
312
313impl Drop for SzEnvironmentCore {
314 fn drop(&mut self) {
315 if !self.is_destroyed() {
319 self.is_destroyed
321 .store(true, std::sync::atomic::Ordering::Relaxed);
322 }
323 }
324}