sz_rust_sdk/ffi/
helpers.rs1use crate::error::{SzError, SzResult};
4use libc::{c_char, size_t};
5use std::ffi::{CStr, CString};
6use std::ptr;
7
8pub(crate) fn str_to_c_string(s: &str) -> SzResult<CString> {
10 CString::new(s).map_err(SzError::from)
11}
12
13pub(crate) fn optional_str_to_c_ptr(s: Option<&str>) -> SzResult<*const c_char> {
15 match s {
16 Some(s) => {
17 let c_string = str_to_c_string(s)?;
18 Ok(c_string.into_raw() as *const c_char)
20 }
21 None => Ok(ptr::null()),
22 }
23}
24
25pub(crate) unsafe fn c_str_to_string(ptr: *mut c_char) -> SzResult<String> {
32 if ptr.is_null() {
33 return Ok(String::new());
34 }
35
36 let c_str = unsafe { CStr::from_ptr(ptr) };
37 let result = match c_str.to_str() {
38 Ok(s) => Ok(s.to_string()),
39 Err(_) => {
40 let bytes = c_str.to_bytes();
43 Ok(hex::encode(bytes))
44 }
45 };
46
47 unsafe { super::bindings::Sz_free(ptr) };
49
50 result
51}
52
53pub(crate) unsafe fn c_str_to_string_no_free(ptr: *mut c_char) -> SzResult<String> {
60 if ptr.is_null() {
61 return Ok(String::new());
62 }
63
64 let c_str = unsafe { CStr::from_ptr(ptr) };
65 match c_str.to_str() {
66 Ok(s) => Ok(s.to_string()),
67 Err(_) => {
68 let bytes = c_str.to_bytes();
70 Ok(hex::encode(bytes))
71 }
72 }
73}
74
75pub(crate) unsafe fn process_pointer_result(
81 result: super::bindings::SzPointerResult,
82) -> SzResult<String> {
83 if result.return_code != 0 {
84 return Err(SzError::from_code(result.return_code));
85 }
86
87 unsafe { c_str_to_string(result.response) }
88}
89
90pub(crate) unsafe fn process_config_pointer_result(
97 result: super::bindings::SzPointerResult,
98) -> SzResult<String> {
99 if result.return_code != 0 {
100 check_config_return_code(result.return_code)?;
101 unreachable!("check_config_return_code should have returned an error");
102 }
103
104 unsafe { c_str_to_string(result.response) }
105}
106
107pub(crate) unsafe fn process_config_pointer_result_bytes(
114 result: super::bindings::SzPointerResult,
115) -> SzResult<Vec<u8>> {
116 if result.return_code != 0 {
117 check_config_return_code(result.return_code)?;
118 unreachable!("check_config_return_code should have returned an error");
119 }
120
121 unsafe { c_str_to_bytes(result.response) }
122}
123
124pub(crate) unsafe fn process_engine_pointer_result(
131 result: super::bindings::SzPointerResult,
132) -> SzResult<String> {
133 if result.return_code != 0 {
134 check_return_code(result.return_code)?;
135 unreachable!("check_return_code should have returned an error");
136 }
137
138 unsafe { c_str_to_string(result.response) }
139}
140
141pub(crate) unsafe fn c_str_to_bytes(ptr: *mut c_char) -> SzResult<Vec<u8>> {
148 if ptr.is_null() {
149 return Ok(Vec::new());
150 }
151
152 let c_str = unsafe { CStr::from_ptr(ptr) };
153 let bytes = c_str.to_bytes().to_vec();
154
155 unsafe { super::bindings::Sz_free(ptr) };
157
158 Ok(bytes)
159}
160
161pub(crate) unsafe fn process_config_mgr_pointer_result(
168 result: super::bindings::SzPointerResult,
169) -> SzResult<String> {
170 if result.return_code != 0 {
171 check_config_mgr_return_code(result.return_code)?;
172 unreachable!("check_config_mgr_return_code should have returned an error");
173 }
174
175 unsafe { c_str_to_string(result.response) }
176}
177
178pub(crate) fn process_config_mgr_long_result(
180 result: super::bindings::SzLongResult,
181) -> SzResult<i64> {
182 if result.return_code != 0 {
183 check_config_mgr_return_code(result.return_code)?;
184 unreachable!("check_config_mgr_return_code should have returned an error");
185 }
186
187 Ok(result.response)
188}
189
190pub(crate) fn process_long_result(result: super::bindings::SzLongResult) -> SzResult<i64> {
192 if result.return_code != 0 {
193 return Err(SzError::from_code(result.return_code));
194 }
195
196 Ok(result.response)
197}
198
199pub(crate) struct ResponseBuffer {
201 pub ptr: *mut c_char,
202 pub size: size_t,
203}
204
205impl Default for ResponseBuffer {
206 fn default() -> Self {
207 Self::new()
208 }
209}
210
211impl ResponseBuffer {
212 pub(crate) fn new() -> Self {
213 Self {
214 ptr: ptr::null_mut(),
215 size: 0,
216 }
217 }
218
219 pub(crate) fn as_string(&self) -> SzResult<String> {
220 unsafe { c_str_to_string(self.ptr) }
221 }
222}
223
224impl Drop for ResponseBuffer {
225 fn drop(&mut self) {
226 if !self.ptr.is_null() {
227 unsafe {
228 super::bindings::Sz_free(self.ptr);
229 }
230 }
231 }
232}
233
234pub(crate) fn check_return_code(return_code: i64) -> SzResult<()> {
236 if return_code == 0 {
237 Ok(())
238 } else {
239 let mut buffer: Vec<u8> = vec![0; 1024];
240 let buffer_len = buffer.len() as i64;
241
242 let error_msg = unsafe {
243 let actual_len =
244 super::bindings::Sz_getLastException(buffer.as_mut_ptr() as *mut i8, buffer_len);
245
246 if actual_len > 0 && actual_len < buffer_len {
247 let string_len = if actual_len > 0 {
250 (actual_len as usize) - 1
251 } else {
252 0
253 };
254 buffer.truncate(string_len);
255 String::from_utf8_lossy(&buffer).to_string()
256 } else {
257 format!("Unknown error (code: {})", return_code)
258 }
259 };
260
261 match return_code {
263 -1 => Err(SzError::unknown(error_msg)),
264 -2 => Err(SzError::configuration(error_msg)),
265 -3 => Err(SzError::bad_input(error_msg)),
266 -4 => Err(SzError::retryable(error_msg)),
267 -5 => Err(SzError::unrecoverable(error_msg)),
268 -6 => Err(SzError::not_found(error_msg)),
269 -7 => Err(SzError::license(error_msg)),
270 -8 => Err(SzError::database(error_msg)),
271 _ => Err(SzError::unknown(error_msg)),
272 }
273 }
274}
275
276pub(crate) fn check_config_return_code(return_code: i64) -> SzResult<()> {
278 if return_code == 0 {
279 Ok(())
280 } else {
281 let mut buffer: Vec<u8> = vec![0; 1024];
282 let buffer_len = buffer.len() as i64;
283
284 let error_msg = unsafe {
285 let actual_len = super::bindings::SzConfig_getLastException(
286 buffer.as_mut_ptr() as *mut i8,
287 buffer_len,
288 );
289
290 if actual_len > 0 && actual_len < buffer_len {
291 let string_len = if actual_len > 0 {
292 (actual_len as usize) - 1
293 } else {
294 0
295 };
296 buffer.truncate(string_len);
297 String::from_utf8_lossy(&buffer).to_string()
298 } else {
299 format!("Unknown Config error (code: {})", return_code)
300 }
301 };
302
303 match return_code {
305 -1 => Err(SzError::unknown(error_msg)),
306 -2 => Err(SzError::configuration(error_msg)),
307 -3 => Err(SzError::bad_input(error_msg)),
308 -4 => Err(SzError::retryable(error_msg)),
309 -5 => Err(SzError::unrecoverable(error_msg)),
310 -6 => Err(SzError::not_found(error_msg)),
311 -7 => Err(SzError::license(error_msg)),
312 -8 => Err(SzError::database(error_msg)),
313 _ => Err(SzError::unknown(error_msg)),
314 }
315 }
316}
317
318pub(crate) fn check_config_mgr_return_code(return_code: i64) -> SzResult<()> {
320 if return_code == 0 {
321 Ok(())
322 } else {
323 let mut buffer: Vec<u8> = vec![0; 1024];
324 let buffer_len = buffer.len() as i64;
325
326 let error_msg = unsafe {
327 let actual_len = super::bindings::SzConfigMgr_getLastException(
328 buffer.as_mut_ptr() as *mut i8,
329 buffer_len,
330 );
331
332 if actual_len > 0 && actual_len < buffer_len {
333 let string_len = if actual_len > 0 {
334 (actual_len as usize) - 1
335 } else {
336 0
337 };
338 buffer.truncate(string_len);
339 String::from_utf8_lossy(&buffer).to_string()
340 } else {
341 format!("Unknown ConfigMgr error (code: {})", return_code)
342 }
343 };
344
345 match return_code {
347 -1 => Err(SzError::unknown(error_msg)),
348 -2 => Err(SzError::configuration(error_msg)),
349 -3 => Err(SzError::bad_input(error_msg)),
350 -4 => Err(SzError::retryable(error_msg)),
351 -5 => Err(SzError::unrecoverable(error_msg)),
352 -6 => Err(SzError::not_found(error_msg)),
353 -7 => Err(SzError::license(error_msg)),
354 -8 => Err(SzError::database(error_msg)),
355 _ => Err(SzError::unknown(error_msg)),
356 }
357 }
358}
359
360pub(crate) fn check_product_return_code(return_code: i64) -> SzResult<()> {
362 if return_code == 0 {
363 Ok(())
364 } else {
365 let mut buffer: Vec<u8> = vec![0; 1024];
366 let buffer_len = buffer.len() as i64;
367
368 let error_msg = unsafe {
369 let actual_len = super::bindings::SzProduct_getLastException(
370 buffer.as_mut_ptr() as *mut i8,
371 buffer_len,
372 );
373
374 if actual_len > 0 && actual_len < buffer_len {
375 let string_len = if actual_len > 0 {
376 (actual_len as usize) - 1
377 } else {
378 0
379 };
380 buffer.truncate(string_len);
381 String::from_utf8_lossy(&buffer).to_string()
382 } else {
383 format!("Unknown error (code: {})", return_code)
384 }
385 };
386
387 match return_code {
389 -1 => Err(SzError::unknown(error_msg)),
390 -2 => Err(SzError::configuration(error_msg)),
391 -3 => Err(SzError::bad_input(error_msg)),
392 -4 => Err(SzError::retryable(error_msg)),
393 -5 => Err(SzError::unrecoverable(error_msg)),
394 -6 => Err(SzError::not_found(error_msg)),
395 -7 => Err(SzError::license(error_msg)),
396 -8 => Err(SzError::database(error_msg)),
397 _ => Err(SzError::unknown(error_msg)),
398 }
399 }
400}
401
402#[deprecated(note = "Use check_return_code directly")]
404pub(crate) fn check_return_code_i64(return_code: i64) -> SzResult<()> {
405 check_return_code(return_code)
406}
407
408#[doc(hidden)]
410#[macro_export]
411macro_rules! ffi_call {
412 ($ffi_fn:expr) => {{
413 #[allow(clippy::macro_metavars_in_unsafe)]
414 let result = unsafe { $ffi_fn };
415 $crate::ffi::helpers::check_return_code(result)?;
416 }};
417}
418
419#[doc(hidden)]
421#[macro_export]
422macro_rules! ffi_call_config {
423 ($ffi_fn:expr) => {{
424 #[allow(clippy::macro_metavars_in_unsafe)]
425 let result = unsafe { $ffi_fn };
426 $crate::ffi::helpers::check_config_return_code(result)?;
427 }};
428}
429
430#[doc(hidden)]
432#[macro_export]
433macro_rules! ffi_call_config_mgr {
434 ($ffi_fn:expr) => {{
435 #[allow(clippy::macro_metavars_in_unsafe)]
436 let result = unsafe { $ffi_fn };
437 $crate::ffi::helpers::check_config_mgr_return_code(result)?;
438 }};
439}
440
441#[doc(hidden)]
443#[macro_export]
444macro_rules! ffi_call_product {
445 ($ffi_fn:expr) => {{
446 #[allow(clippy::macro_metavars_in_unsafe)]
447 let result = unsafe { $ffi_fn };
448 $crate::ffi::helpers::check_product_return_code(result)?;
449 }};
450}
451
452#[doc(hidden)]
454#[macro_export]
455macro_rules! ffi_call_i64 {
456 ($ffi_fn:expr) => {{
457 #[allow(clippy::macro_metavars_in_unsafe)]
458 let result = unsafe { $ffi_fn };
459 $crate::ffi::helpers::check_return_code(result)?;
460 }};
461}
462
463#[doc(hidden)]
465#[macro_export]
466macro_rules! ffi_call_with_response {
467 ($ffi_fn:expr) => {{
468 let mut response = $crate::ffi::helpers::ResponseBuffer::new();
469 let result = unsafe { $ffi_fn(&mut response.ptr, &mut response.size) };
470 $crate::ffi::helpers::check_return_code(result)?;
471 response.as_string()
472 }};
473}