Skip to main content

hdds_c/
info.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2// Copyright (c) 2025-2026 naskel.com
3
4//! Participant and entity information getters for HDDS C FFI
5
6use std::ffi::CString;
7use std::os::raw::c_char;
8use std::ptr;
9use std::sync::Arc;
10
11use hdds::api::{DataReader, DataWriter, Participant};
12
13use super::{BytePayload, HddsDataReader, HddsDataWriter, HddsError, HddsParticipant};
14
15// =============================================================================
16// Participant Information
17// =============================================================================
18
19/// Get the participant name
20///
21/// # Safety
22/// - `participant` must be a valid pointer returned from `hdds_participant_create`
23/// - Returns a pointer to an internal string, valid until participant is destroyed
24///
25/// # Returns
26/// Pointer to null-terminated participant name, or NULL on error
27#[no_mangle]
28pub unsafe extern "C" fn hdds_participant_name(participant: *mut HddsParticipant) -> *const c_char {
29    if participant.is_null() {
30        return ptr::null();
31    }
32
33    let participant_ref = &*participant.cast::<Arc<Participant>>();
34
35    // We need to return a stable pointer, so we leak a CString
36    // This is acceptable since participant names are typically static
37    match CString::new(participant_ref.name()) {
38        Ok(cstr) => {
39            let ptr = cstr.as_ptr();
40            std::mem::forget(cstr); // Leak intentionally - freed when participant destroyed
41            ptr
42        }
43        Err(_) => ptr::null(),
44    }
45}
46
47/// Get the participant domain ID
48///
49/// # Safety
50/// - `participant` must be a valid pointer returned from `hdds_participant_create`
51///
52/// # Returns
53/// Domain ID (default 0), or 0xFFFFFFFF on error
54#[no_mangle]
55pub unsafe extern "C" fn hdds_participant_domain_id(participant: *mut HddsParticipant) -> u32 {
56    if participant.is_null() {
57        return 0xFFFF_FFFF;
58    }
59
60    let participant_ref = &*participant.cast::<Arc<Participant>>();
61    participant_ref.domain_id()
62}
63
64/// Get the participant ID (unique within domain)
65///
66/// # Safety
67/// - `participant` must be a valid pointer
68///
69/// # Returns
70/// Participant ID, or 0xFF on error
71#[no_mangle]
72pub unsafe extern "C" fn hdds_participant_id(participant: *mut HddsParticipant) -> u8 {
73    if participant.is_null() {
74        return 0xFF;
75    }
76
77    let participant_ref = &*participant.cast::<Arc<Participant>>();
78    participant_ref.participant_id()
79}
80
81// =============================================================================
82// DataWriter Information
83// =============================================================================
84
85/// Get the topic name for a writer
86///
87/// # Safety
88/// - `writer` must be a valid pointer
89/// - `buf` must point to a buffer of at least `buf_len` bytes
90/// - `out_len` must be a valid pointer
91///
92/// # Returns
93/// `HddsError::HddsOk` on success, writes topic name to buffer
94#[no_mangle]
95pub unsafe extern "C" fn hdds_writer_topic_name(
96    writer: *mut HddsDataWriter,
97    buf: *mut c_char,
98    buf_len: usize,
99    out_len: *mut usize,
100) -> HddsError {
101    if writer.is_null() || buf.is_null() || out_len.is_null() {
102        return HddsError::HddsInvalidArgument;
103    }
104
105    let writer_ref = &*writer.cast::<DataWriter<BytePayload>>();
106    let name = writer_ref.topic_name();
107
108    let name_len = name.len();
109    *out_len = name_len;
110
111    if buf_len < name_len + 1 {
112        return HddsError::HddsOutOfMemory;
113    }
114
115    ptr::copy_nonoverlapping(name.as_ptr(), buf.cast::<u8>(), name_len);
116    *buf.add(name_len) = 0; // Null terminator
117
118    HddsError::HddsOk
119}
120
121// =============================================================================
122// DataReader Information
123// =============================================================================
124
125/// Get the topic name for a reader
126///
127/// # Safety
128/// - `reader` must be a valid pointer
129/// - `buf` must point to a buffer of at least `buf_len` bytes
130/// - `out_len` must be a valid pointer
131///
132/// # Returns
133/// `HddsError::HddsOk` on success, writes topic name to buffer
134#[no_mangle]
135pub unsafe extern "C" fn hdds_reader_topic_name(
136    reader: *mut HddsDataReader,
137    buf: *mut c_char,
138    buf_len: usize,
139    out_len: *mut usize,
140) -> HddsError {
141    if reader.is_null() || buf.is_null() || out_len.is_null() {
142        return HddsError::HddsInvalidArgument;
143    }
144
145    let reader_ref = &*reader.cast::<DataReader<BytePayload>>();
146    let name = reader_ref.topic_name();
147
148    let name_len = name.len();
149    *out_len = name_len;
150
151    if buf_len < name_len + 1 {
152        return HddsError::HddsOutOfMemory;
153    }
154
155    ptr::copy_nonoverlapping(name.as_ptr(), buf.cast::<u8>(), name_len);
156    *buf.add(name_len) = 0; // Null terminator
157
158    HddsError::HddsOk
159}