Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 56 additions & 52 deletions rustecal-core/src/configuration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,88 +7,92 @@
//! default settings or loading from a YAML file, and automatically
//! frees the underlying C object on drop.

use std::{ffi::{CStr, CString}, path::Path, ops::{Deref, DerefMut}};
use thiserror::Error;
use rustecal_sys as sys;
use std::{
ffi::{CStr, CString},
ops::{Deref, DerefMut},
path::Path,
};
use thiserror::Error;

/// Errors that can occur when creating or loading a Configuration
#[derive(Debug, Error)]
pub enum ConfigError {
#[error("Received null pointer from eCAL_Configuration_New")]
NullPointer,
#[error("Invalid file path: {0}")]
InvalidPath(String),
#[error("Received null pointer from eCAL_Configuration_New")]
NullPointer,
#[error("Invalid file path: {0}")]
InvalidPath(String),
}

/// Safe Rust wrapper around eCAL_Configuration
pub struct Configuration {
inner: *mut sys::eCAL_Configuration,
inner: *mut sys::eCAL_Configuration,
}

unsafe impl Send for Configuration {}
unsafe impl Sync for Configuration {}

impl Configuration {
/// Creates a new Configuration with default values loaded via eCAL_Configuration_InitFromConfig
pub fn new() -> Result<Self, ConfigError> {
let cfg = unsafe { sys::eCAL_Configuration_New() };
if cfg.is_null() {
return Err(ConfigError::NullPointer);
/// Creates a new Configuration with default values loaded via eCAL_Configuration_InitFromConfig
pub fn new() -> Result<Self, ConfigError> {
let cfg = unsafe { sys::eCAL_Configuration_New() };
if cfg.is_null() {
return Err(ConfigError::NullPointer);
}
unsafe { sys::eCAL_Configuration_InitFromConfig(cfg) };
Ok(Configuration { inner: cfg })
}
unsafe { sys::eCAL_Configuration_InitFromConfig(cfg) };
Ok(Configuration { inner: cfg })
}

/// Loads a Configuration from a YAML file at the given path
pub fn from_file(path: &str) -> Result<Self, ConfigError> {
if !Path::new(path).exists() {
return Err(ConfigError::InvalidPath(path.to_string()));
/// Loads a Configuration from a YAML file at the given path
pub fn from_file(path: &str) -> Result<Self, ConfigError> {
if !Path::new(path).exists() {
return Err(ConfigError::InvalidPath(path.to_string()));
}
let c_path = CString::new(path).map_err(|_| ConfigError::InvalidPath(path.to_string()))?;
let cfg = unsafe { sys::eCAL_Configuration_New() };
if cfg.is_null() {
return Err(ConfigError::NullPointer);
}
unsafe { sys::eCAL_Configuration_InitFromFile(cfg, c_path.as_ptr()) };
Ok(Configuration { inner: cfg })
}
let c_path = CString::new(path).map_err(|_| ConfigError::InvalidPath(path.to_string()))?;
let cfg = unsafe { sys::eCAL_Configuration_New() };
if cfg.is_null() {
return Err(ConfigError::NullPointer);
}
unsafe { sys::eCAL_Configuration_InitFromFile(cfg, c_path.as_ptr()) };
Ok(Configuration { inner: cfg })
}

/// Returns the path of the loaded configuration file, if any
pub fn file_path(&self) -> Option<String> {
unsafe {
let p = sys::eCAL_Configuration_GetConfigurationFilePath(self.inner);
if p.is_null() {
None
} else {
Some(CStr::from_ptr(p).to_string_lossy().into_owned())
}
/// Returns the path of the loaded configuration file, if any
pub fn file_path(&self) -> Option<String> {
unsafe {
let p = sys::eCAL_Configuration_GetConfigurationFilePath(self.inner);
if p.is_null() {
None
} else {
Some(CStr::from_ptr(p).to_string_lossy().into_owned())
}
}
}
}

/// Returns a raw pointer to the underlying eCAL_Configuration for FFI calls
pub(crate) fn as_ptr(&self) -> *const sys::eCAL_Configuration {
self.inner as *const _
}
/// Returns a raw pointer to the underlying eCAL_Configuration for FFI calls
pub(crate) fn as_ptr(&self) -> *const sys::eCAL_Configuration {
self.inner as *const _
}
}

/// Allow transparent access to the underlying C struct
impl Deref for Configuration {
type Target = sys::eCAL_Configuration;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner }
}
type Target = sys::eCAL_Configuration;
fn deref(&self) -> &Self::Target {
unsafe { &*self.inner }
}
}

/// Allow mutable access to the underlying C struct
impl DerefMut for Configuration {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.inner }
}
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.inner }
}
}

impl Drop for Configuration {
/// Deletes the underlying eCAL_Configuration on drop
fn drop(&mut self) {
unsafe { sys::eCAL_Configuration_Delete(self.inner) };
}
/// Deletes the underlying eCAL_Configuration on drop
fn drop(&mut self) {
unsafe { sys::eCAL_Configuration_Delete(self.inner) };
}
}
6 changes: 2 additions & 4 deletions rustecal-core/src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ impl Ecal {
// Convert the unit name (if any), mapping CString errors
let (name_ptr, _): (*const i8, Option<CString>) = if let Some(name) = unit_name {
let c = CString::new(name)
.map_err(|e| RustecalError::Internal(format!("invalid unit name: {}", e)))?;
.map_err(|e| RustecalError::Internal(format!("invalid unit name: {e}")))?;
(c.as_ptr(), Some(c))
} else {
(ptr::null(), None)
Expand All @@ -57,9 +57,7 @@ impl Ecal {
.unwrap_or(ptr::null_mut());

// Call the C API and map its return code
let ret = unsafe {
rustecal_sys::eCAL_Initialize(name_ptr, &components.bits(), cfg_ptr)
};
let ret = unsafe { rustecal_sys::eCAL_Initialize(name_ptr, &components.bits(), cfg_ptr) };
check(ret)
}

Expand Down
2 changes: 1 addition & 1 deletion rustecal-core/src/core_types/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! Common eCAL types shared across pubsub and service layers.

pub mod monitoring;
pub mod logging;
pub mod monitoring;
10 changes: 5 additions & 5 deletions rustecal-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
//!
//! This crate is typically re-exported by the `rustecal` crate.

pub mod core;
pub mod components;
pub mod configuration;
pub mod core;
pub mod core_types;
pub mod error;
pub mod types;
pub mod log;
pub mod log_level;
pub mod core_types;
pub mod monitoring;
pub mod types;

// Re‑exports for ergonomic access:
pub use core::Ecal;
pub use components::EcalComponents;
pub use configuration::Configuration;
pub use core::Ecal;
pub use core_types::logging::LogMessage;
pub use error::RustecalError;
pub use log::Log;
pub use log_level::LogLevel;
pub use core_types::logging::LogMessage;
6 changes: 3 additions & 3 deletions rustecal-core/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//! logging at various severity levels, as well as retrieval of current log entries.

use crate::core_types::logging::LogMessage;
use crate::log_level::LogLevel;
use crate::error::RustecalError;
use crate::log_level::LogLevel;
use std::{ffi::CString, ptr, slice};

/// Provides logging functions to emit and retrieve messages via the eCAL runtime.
Expand All @@ -16,8 +16,8 @@ impl Log {
///
/// Any interior NUL in `message` is replaced with `"<invalid UTF-8>"`.
pub fn log(level: LogLevel, message: &str) {
let cstr = CString::new(message)
.unwrap_or_else(|_| CString::new("<invalid UTF-8>").unwrap());
let cstr =
CString::new(message).unwrap_or_else(|_| CString::new("<invalid UTF-8>").unwrap());

unsafe {
rustecal_sys::eCAL_Logging_Log(level.into(), cstr.as_ptr());
Expand Down
34 changes: 17 additions & 17 deletions rustecal-core/src/log_level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,40 +22,40 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogLevel {
/// No logging.
None = 0,
None = 0,
/// Informational messages.
Info = 1,
Info = 1,
/// Warnings.
Warning = 2,
/// Errors.
Error = 4,
Error = 4,
/// Fatal errors.
Fatal = 8,
Fatal = 8,
/// Debug level 1.
Debug1 = 16,
Debug1 = 16,
/// Debug level 2.
Debug2 = 32,
Debug2 = 32,
/// Debug level 3.
Debug3 = 64,
Debug3 = 64,
/// Debug level 4.
Debug4 = 128,
Debug4 = 128,
/// All levels.
All = 255,
All = 255,
}

impl From<i32> for LogLevel {
fn from(value: i32) -> Self {
match value {
1 => LogLevel::Info,
2 => LogLevel::Warning,
4 => LogLevel::Error,
8 => LogLevel::Fatal,
16 => LogLevel::Debug1,
32 => LogLevel::Debug2,
64 => LogLevel::Debug3,
1 => LogLevel::Info,
2 => LogLevel::Warning,
4 => LogLevel::Error,
8 => LogLevel::Fatal,
16 => LogLevel::Debug1,
32 => LogLevel::Debug2,
64 => LogLevel::Debug3,
128 => LogLevel::Debug4,
255 => LogLevel::All,
_ => LogLevel::None,
_ => LogLevel::None,
}
}
}
Expand Down
9 changes: 3 additions & 6 deletions rustecal-core/src/monitoring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
//! a safe Rust API to access a snapshot of the middleware's state.

use crate::core_types::monitoring::{
MonitoringSnapshot, ProcessInfo, TopicInfo, ServerInfo, ClientInfo,
ClientInfo, MonitoringSnapshot, ProcessInfo, ServerInfo, TopicInfo,
};
use crate::error::RustecalError;
use std::{ptr, slice};
Expand All @@ -25,13 +25,10 @@ impl Monitoring {
/// when a snapshot *should* have been provided.
pub fn get_snapshot() -> Result<MonitoringSnapshot, RustecalError> {
// 1) Prepare a null pointer for the C function to fill in
let mut raw: *mut rustecal_sys::eCAL_Monitoring_SMonitoring =
ptr::null_mut();
let mut raw: *mut rustecal_sys::eCAL_Monitoring_SMonitoring = ptr::null_mut();

// 2) Call the FFI: non‑zero means “no snapshot available”
let ret = unsafe {
rustecal_sys::eCAL_Monitoring_GetMonitoring(&mut raw, ptr::null())
};
let ret = unsafe { rustecal_sys::eCAL_Monitoring_GetMonitoring(&mut raw, ptr::null()) };

// 3) If nothing to monitor, return an empty snapshot
if ret != 0 {
Expand Down
11 changes: 5 additions & 6 deletions rustecal-pubsub/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,22 @@
//! - `TypedSubscriber<T>`
//! - Supported types: `StringMessage`, `BytesMessage`, `ProtobufMessage<T>`


// Re-export core init & types
pub use rustecal_core::{Ecal, EcalComponents};

// Sub‑modules
pub mod types;
pub mod payload_writer;
pub mod publisher;
pub mod subscriber;
pub mod typed_publisher;
pub mod typed_subscriber;
pub mod payload_writer;
pub mod types;

// Public API
pub use payload_writer::PayloadWriter;
pub use publisher::Publisher;
pub use subscriber::Subscriber;
pub use typed_publisher::TypedPublisher;
pub use typed_publisher::PublisherMessage;
pub use typed_subscriber::TypedSubscriber;
pub use typed_publisher::TypedPublisher;
pub use typed_subscriber::SubscriberMessage;
pub use payload_writer::PayloadWriter;
pub use typed_subscriber::TypedSubscriber;
14 changes: 11 additions & 3 deletions rustecal-pubsub/src/payload_writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// with eCAL's `SendPayloadWriter` API, using mutable references rather than owning values.

use std::cell::RefCell;
use std::os::raw::{c_void, c_int};
use std::os::raw::{c_int, c_void};

/// A zero‐copy payload writer: you fill the shared‐memory buffer in place.
pub trait PayloadWriter {
Expand Down Expand Up @@ -35,7 +35,11 @@ pub(crate) unsafe extern "C" fn write_full_cb(buffer: *mut c_void, size: usize)
if let Some(writer_ptr) = *cell.borrow() {
let writer: &mut dyn PayloadWriter = &mut *writer_ptr;
let buf = std::slice::from_raw_parts_mut(buffer as *mut u8, size);
if writer.write_full(buf) { 0 } else { -1 }
if writer.write_full(buf) {
0
} else {
-1
}
} else {
-1
}
Expand All @@ -48,7 +52,11 @@ pub(crate) unsafe extern "C" fn write_mod_cb(buffer: *mut c_void, size: usize) -
if let Some(writer_ptr) = *cell.borrow() {
let writer: &mut dyn PayloadWriter = &mut *writer_ptr;
let buf = std::slice::from_raw_parts_mut(buffer as *mut u8, size);
if writer.write_modified(buf) { 0 } else { -1 }
if writer.write_modified(buf) {
0
} else {
-1
}
} else {
-1
}
Expand Down
Loading
Loading