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}