use super::context::{CContext, get_context_ref};
use super::{ErrorCode, cstr_to_str};
use std::ffi::{CString, c_char};
#[repr(C)]
pub struct CTopicInfo {
pub name: *mut c_char,
pub type_name: *mut c_char,
}
#[repr(C)]
pub struct CNodeInfo {
pub name: *mut c_char,
pub namespace: *mut c_char,
}
#[repr(C)]
pub struct CServiceInfo {
pub name: *mut c_char,
pub type_name: *mut c_char,
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_get_topic_names_and_types(
ctx: *mut CContext,
out_topics: *mut *mut CTopicInfo,
out_count: *mut usize,
) -> i32 {
if out_topics.is_null() || out_count.is_null() {
return ErrorCode::NullPointer as i32;
}
unsafe {
let ctx_ref = match get_context_ref(ctx) {
Some(c) => c,
None => return ErrorCode::NullPointer as i32,
};
let topics = ctx_ref.graph().get_topic_names_and_types();
let count = topics.len();
if count == 0 {
*out_topics = std::ptr::null_mut();
*out_count = 0;
return ErrorCode::Success as i32;
}
let layout = std::alloc::Layout::array::<CTopicInfo>(count).unwrap();
let ptr = std::alloc::alloc(layout) as *mut CTopicInfo;
if ptr.is_null() {
return ErrorCode::Unknown as i32;
}
for (i, (name, type_name)) in topics.into_iter().enumerate() {
let c_name = CString::new(name).unwrap_or_default();
let c_type = CString::new(type_name).unwrap_or_default();
std::ptr::write(
ptr.add(i),
CTopicInfo {
name: c_name.into_raw(),
type_name: c_type.into_raw(),
},
);
}
*out_topics = ptr;
*out_count = count;
ErrorCode::Success as i32
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_free_topics(topics: *mut CTopicInfo, count: usize) {
if topics.is_null() || count == 0 {
return;
}
unsafe {
for i in 0..count {
let topic = &*topics.add(i);
if !topic.name.is_null() {
let _ = CString::from_raw(topic.name);
}
if !topic.type_name.is_null() {
let _ = CString::from_raw(topic.type_name);
}
}
let layout = std::alloc::Layout::array::<CTopicInfo>(count).unwrap();
std::alloc::dealloc(topics as *mut u8, layout);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_get_node_names(
ctx: *mut CContext,
out_nodes: *mut *mut CNodeInfo,
out_count: *mut usize,
) -> i32 {
if out_nodes.is_null() || out_count.is_null() {
return ErrorCode::NullPointer as i32;
}
unsafe {
let ctx_ref = match get_context_ref(ctx) {
Some(c) => c,
None => return ErrorCode::NullPointer as i32,
};
let nodes = ctx_ref.graph().get_node_names();
let count = nodes.len();
if count == 0 {
*out_nodes = std::ptr::null_mut();
*out_count = 0;
return ErrorCode::Success as i32;
}
let layout = std::alloc::Layout::array::<CNodeInfo>(count).unwrap();
let ptr = std::alloc::alloc(layout) as *mut CNodeInfo;
if ptr.is_null() {
return ErrorCode::Unknown as i32;
}
for (i, (name, namespace)) in nodes.into_iter().enumerate() {
let c_name = CString::new(name).unwrap_or_default();
let c_ns = CString::new(namespace).unwrap_or_default();
std::ptr::write(
ptr.add(i),
CNodeInfo {
name: c_name.into_raw(),
namespace: c_ns.into_raw(),
},
);
}
*out_nodes = ptr;
*out_count = count;
ErrorCode::Success as i32
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_free_nodes(nodes: *mut CNodeInfo, count: usize) {
if nodes.is_null() || count == 0 {
return;
}
unsafe {
for i in 0..count {
let node = &*nodes.add(i);
if !node.name.is_null() {
let _ = CString::from_raw(node.name);
}
if !node.namespace.is_null() {
let _ = CString::from_raw(node.namespace);
}
}
let layout = std::alloc::Layout::array::<CNodeInfo>(count).unwrap();
std::alloc::dealloc(nodes as *mut u8, layout);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_get_service_names_and_types(
ctx: *mut CContext,
out_services: *mut *mut CServiceInfo,
out_count: *mut usize,
) -> i32 {
if out_services.is_null() || out_count.is_null() {
return ErrorCode::NullPointer as i32;
}
unsafe {
let ctx_ref = match get_context_ref(ctx) {
Some(c) => c,
None => return ErrorCode::NullPointer as i32,
};
let services = ctx_ref.graph().get_service_names_and_types();
let count = services.len();
if count == 0 {
*out_services = std::ptr::null_mut();
*out_count = 0;
return ErrorCode::Success as i32;
}
let layout = std::alloc::Layout::array::<CServiceInfo>(count).unwrap();
let ptr = std::alloc::alloc(layout) as *mut CServiceInfo;
if ptr.is_null() {
return ErrorCode::Unknown as i32;
}
for (i, (name, type_name)) in services.into_iter().enumerate() {
let c_name = CString::new(name).unwrap_or_default();
let c_type = CString::new(type_name).unwrap_or_default();
std::ptr::write(
ptr.add(i),
CServiceInfo {
name: c_name.into_raw(),
type_name: c_type.into_raw(),
},
);
}
*out_services = ptr;
*out_count = count;
ErrorCode::Success as i32
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_free_services(services: *mut CServiceInfo, count: usize) {
if services.is_null() || count == 0 {
return;
}
unsafe {
for i in 0..count {
let svc = &*services.add(i);
if !svc.name.is_null() {
let _ = CString::from_raw(svc.name);
}
if !svc.type_name.is_null() {
let _ = CString::from_raw(svc.type_name);
}
}
let layout = std::alloc::Layout::array::<CServiceInfo>(count).unwrap();
std::alloc::dealloc(services as *mut u8, layout);
}
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn hiroz_graph_node_exists(
ctx: *mut CContext,
name: *const c_char,
namespace: *const c_char,
) -> i32 {
unsafe {
let ctx_ref = match get_context_ref(ctx) {
Some(c) => c,
None => return ErrorCode::NullPointer as i32,
};
let name_str = match cstr_to_str(name) {
Ok(s) => s,
Err(_) => return ErrorCode::InvalidUtf8 as i32,
};
let namespace_str = if namespace.is_null() {
"/"
} else {
match cstr_to_str(namespace) {
Ok(s) => s,
Err(_) => return ErrorCode::InvalidUtf8 as i32,
}
};
let node_key: crate::entity::NodeKey = (namespace_str.to_string(), name_str.to_string());
if ctx_ref.graph().node_exists(node_key) {
1
} else {
0
}
}
}