|
14 | 14 | //! application and [`Ecal::finalize`] at shutdown. |
15 | 15 |
|
16 | 16 | use std::ffi::{CStr, CString}; |
| 17 | +use std::ptr; |
| 18 | + |
17 | 19 | use crate::components::EcalComponents; |
| 20 | +use crate::error::{check, RustecalError}; |
18 | 21 | use crate::types::Version; |
19 | 22 |
|
20 | | -/// Provides access to the core initialization, shutdown, and state-checking functions of eCAL. |
| 23 | +/// Provides access to the core initialization, shutdown, and state‑checking functions of eCAL. |
21 | 24 | pub struct Ecal; |
22 | 25 |
|
23 | 26 | impl Ecal { |
24 | 27 | /// Initializes the eCAL runtime system. |
25 | 28 | /// |
26 | | - /// This function must be called before using any publisher, subscriber, or service functionality. |
27 | | - /// |
28 | 29 | /// # Arguments |
29 | 30 | /// |
30 | | - /// * `unit_name` - Optional name to identify this process in eCAL (e.g. in monitoring). |
31 | | - /// * `components` - Bitmask of which subsystems (e.g. pub/sub, monitoring) to enable. |
32 | | - /// |
33 | | - /// # Returns |
34 | | - /// |
35 | | - /// Returns `Ok(())` on success, or `Err(code)` with a non-zero error code. |
36 | | - pub fn initialize(unit_name: Option<&str>, components: EcalComponents) -> Result<(), i32> { |
37 | | - let cstr = unit_name.map(|s| CString::new(s).unwrap()); |
38 | | - let ptr = cstr.as_ref().map_or(std::ptr::null(), |c| c.as_ptr()); |
39 | | - |
40 | | - let result = unsafe { |
41 | | - rustecal_sys::eCAL_Initialize(ptr, &components.bits(), std::ptr::null()) |
| 31 | + /// * `unit_name` – Optional name to identify this process in eCAL. |
| 32 | + /// * `components` – Bitmask of which subsystems to enable. |
| 33 | + /// |
| 34 | + /// # Errors |
| 35 | + /// |
| 36 | + /// Returns `Err(RustecalError::Ecal{..})` on any non‑zero C return code, |
| 37 | + /// or `RustecalError::Internal` if the unit name contains an interior NUL. |
| 38 | + pub fn initialize( |
| 39 | + unit_name: Option<&str>, |
| 40 | + components: EcalComponents, |
| 41 | + ) -> Result<(), RustecalError> { |
| 42 | + // Convert the unit name (if any), mapping CString errors |
| 43 | + let (name_ptr, _): ( *const i8, Option<CString> ) = if let Some(name) = unit_name { |
| 44 | + let c = CString::new(name) |
| 45 | + .map_err(|e| RustecalError::Internal(format!("invalid unit name: {}", e)))?; |
| 46 | + (c.as_ptr(), Some(c)) |
| 47 | + } else { |
| 48 | + (ptr::null(), None) |
42 | 49 | }; |
43 | 50 |
|
44 | | - if result == 0 { |
45 | | - Ok(()) |
46 | | - } else { |
47 | | - Err(result) |
48 | | - } |
| 51 | + // Call the C API and map its return code |
| 52 | + let ret = unsafe { rustecal_sys::eCAL_Initialize(name_ptr, &components.bits(), ptr::null()) }; |
| 53 | + check(ret) |
49 | 54 | } |
50 | 55 |
|
51 | 56 | /// Finalizes and shuts down the eCAL runtime system. |
52 | 57 | /// |
53 | | - /// After calling this function, all publishers, subscribers, and services are invalidated. |
| 58 | + /// After calling this, all publishers, subscribers, and services are invalidated. |
54 | 59 | pub fn finalize() { |
55 | 60 | unsafe { |
56 | 61 | rustecal_sys::eCAL_Finalize(); |
57 | 62 | } |
58 | 63 | } |
59 | 64 |
|
60 | | - /// Checks if the eCAL system is initialized and running properly. |
61 | | - /// |
62 | | - /// This can be used as the main loop condition in long-running processes. |
63 | | - /// |
64 | | - /// # Returns |
65 | | - /// |
66 | | - /// `true` if the system is operational, `false` otherwise. |
| 65 | + /// Returns `true` if the eCAL system is currently operational. |
67 | 66 | pub fn ok() -> bool { |
68 | 67 | unsafe { rustecal_sys::eCAL_Ok() != 0 } |
69 | 68 | } |
70 | 69 |
|
71 | | - /// Checks if the eCAL system has been initialized. |
72 | | - /// |
73 | | - /// This function checks whether any components of the middleware have been initialized. |
74 | | - /// |
75 | | - /// # Returns |
76 | | - /// |
77 | | - /// `true` if initialization has occurred, `false` otherwise. |
| 70 | + /// Returns `true` if *any* eCAL components have been initialized. |
78 | 71 | pub fn is_initialized() -> bool { |
79 | 72 | unsafe { rustecal_sys::eCAL_IsInitialized() != 0 } |
80 | 73 | } |
81 | 74 |
|
82 | | - /// Checks if specific components of eCAL are initialized. |
83 | | - /// |
84 | | - /// This allows querying the status of individual middleware components like pub/sub, monitoring, etc. |
85 | | - /// |
86 | | - /// # Arguments |
87 | | - /// |
88 | | - /// * `components` - Bitmask of components to check. |
89 | | - /// |
90 | | - /// # Returns |
91 | | - /// |
92 | | - /// `true` if the given components are initialized, `false` otherwise. |
| 75 | + /// Returns `true` if the specified components are initialized. |
93 | 76 | pub fn is_component_initialized(components: EcalComponents) -> bool { |
94 | 77 | unsafe { rustecal_sys::eCAL_IsComponentInitialized(components.bits()) != 0 } |
95 | 78 | } |
96 | 79 |
|
97 | | - /// Returns the version string of the eCAL runtime. |
98 | | - /// |
99 | | - /// # Returns |
| 80 | + /// Returns the eCAL version string (e.g. `"6.0.0"`). |
100 | 81 | /// |
101 | | - /// A static string slice with the full version string, e.g. `"5.11.0"`. |
| 82 | + /// This is infallible: if the C pointer is null or contains invalid UTF‑8, |
| 83 | + /// it returns `"unknown"`. |
102 | 84 | pub fn version_string() -> &'static str { |
103 | | - unsafe { |
104 | | - CStr::from_ptr(rustecal_sys::eCAL_GetVersionString()) |
105 | | - .to_str() |
106 | | - .unwrap_or("unknown") |
| 85 | + // SAFETY: eCAL guarantees a static, valid C string here. |
| 86 | + let ptr = unsafe { rustecal_sys::eCAL_GetVersionString() }; |
| 87 | + if ptr.is_null() { |
| 88 | + "unknown" |
| 89 | + } else { |
| 90 | + unsafe { CStr::from_ptr(ptr).to_str().unwrap_or("unknown") } |
107 | 91 | } |
108 | 92 | } |
109 | 93 |
|
110 | | - /// Returns the build date string of the eCAL runtime. |
| 94 | + /// Returns the eCAL build‑date string (e.g. `"01.05.2025"`). |
111 | 95 | /// |
112 | | - /// # Returns |
113 | | - /// |
114 | | - /// A static string slice with the build date string, e.g. `"Apr 2025"`. |
| 96 | + /// This is infallible: if the C pointer is null or contains invalid UTF‑8, |
| 97 | + /// it returns `"unknown"`. |
115 | 98 | pub fn version_date_string() -> &'static str { |
116 | | - unsafe { |
117 | | - CStr::from_ptr(rustecal_sys::eCAL_GetVersionDateString()) |
118 | | - .to_str() |
119 | | - .unwrap_or("unknown") |
| 99 | + let ptr = unsafe { rustecal_sys::eCAL_GetVersionDateString() }; |
| 100 | + if ptr.is_null() { |
| 101 | + "unknown" |
| 102 | + } else { |
| 103 | + unsafe { CStr::from_ptr(ptr).to_str().unwrap_or("unknown") } |
120 | 104 | } |
121 | 105 | } |
122 | 106 |
|
123 | | - /// Returns the version of the eCAL runtime as structured integers. |
124 | | - /// |
125 | | - /// # Returns |
126 | | - /// |
127 | | - /// A [`Version`] struct with fields `major`, `minor`, and `patch`. |
| 107 | + /// Returns the eCAL version as a structured `Version { major, minor, patch }`. |
128 | 108 | pub fn version_struct() -> Version { |
129 | 109 | unsafe { rustecal_sys::eCAL_GetVersion().into() } |
130 | 110 | } |
|
0 commit comments