#![allow(non_camel_case_types)]
#![allow(clippy::missing_safety_doc)]
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
#[cfg(feature = "components")]
use std::ffi::c_void;
#[cfg(feature = "components")]
use std::sync::Arc;
#[cfg(feature = "components")]
use reflow_rt::actor_runtime::Actor;
#[cfg(feature = "components")]
use reflow_rt::graph::types::GraphExport;
#[cfg(feature = "components")]
use reflow_rt::network::subgraph::SubgraphActor;
use crate::actor::rfl_actor;
#[cfg(feature = "components")]
use crate::rfl_status;
use crate::set_last_error;
#[no_mangle]
pub unsafe extern "C" fn rfl_template_actor_new(template_id: *const c_char) -> *mut rfl_actor {
crate::clear_last_error();
if template_id.is_null() {
set_last_error("template_id is null");
return std::ptr::null_mut();
}
let tid = match unsafe { CStr::from_ptr(template_id) }.to_str() {
Ok(s) => s,
Err(_) => {
set_last_error("template_id is not valid UTF-8");
return std::ptr::null_mut();
}
};
if let Some(actor) = reflow_pack_loader::instantiate(tid) {
return Box::into_raw(Box::new(rfl_actor { inner: actor }));
}
#[cfg(feature = "components")]
{
if let Some(actor) = reflow_components::get_actor_for_template(tid) {
return Box::into_raw(Box::new(rfl_actor { inner: actor }));
}
}
set_last_error(format!(
"unknown template id '{tid}' — no loaded pack or bundled catalog entry"
));
std::ptr::null_mut()
}
#[no_mangle]
pub extern "C" fn rfl_template_list_json() -> *mut c_char {
crate::clear_last_error();
let mut ids: Vec<String> = reflow_pack_loader::PACK_REGISTRY.template_ids();
#[cfg(feature = "components")]
{
for k in reflow_components::get_template_mapping().keys() {
if !ids.contains(k) {
ids.push(k.clone());
}
}
}
ids.sort();
match serde_json::to_string(&ids) {
Ok(s) => CString::new(s)
.map(|c| c.into_raw())
.unwrap_or(std::ptr::null_mut()),
Err(e) => {
set_last_error(format!("template list serialize: {e}"));
std::ptr::null_mut()
}
}
}
#[cfg(feature = "components")]
#[no_mangle]
pub unsafe extern "C" fn rfl_subgraph_actor_new_from_json(
graph_export_json: *const c_char,
) -> *mut rfl_actor {
crate::clear_last_error();
if graph_export_json.is_null() {
set_last_error("graph_export_json is null");
return std::ptr::null_mut();
}
let s = match unsafe { CStr::from_ptr(graph_export_json) }.to_str() {
Ok(s) => s,
Err(_) => {
set_last_error("graph_export_json is not valid UTF-8");
return std::ptr::null_mut();
}
};
let export: GraphExport = match serde_json::from_str(s) {
Ok(v) => v,
Err(e) => {
set_last_error(format!("graph_export_json parse: {e}"));
return std::ptr::null_mut();
}
};
let mut actors: std::collections::HashMap<String, Arc<dyn Actor>> =
std::collections::HashMap::new();
for node in export.processes.values() {
if actors.contains_key(&node.component) {
continue;
}
let resolved = reflow_pack_loader::instantiate(&node.component)
.or_else(|| reflow_components::get_actor_for_template(&node.component));
match resolved {
Some(a) => {
actors.insert(node.component.clone(), a);
}
None => {
set_last_error(format!(
"subgraph references unknown component '{}' — register it \
on the parent network first, load a pack that owns it, \
or expose a builder API",
node.component
));
return std::ptr::null_mut();
}
}
}
match SubgraphActor::from_graph_export(&export, actors) {
Ok(sg) => Box::into_raw(Box::new(rfl_actor {
inner: Arc::new(sg) as Arc<dyn Actor>,
})),
Err(e) => {
set_last_error(format!("subgraph build: {e}"));
std::ptr::null_mut()
}
}
}
#[cfg(feature = "components")]
#[allow(dead_code)]
fn _assert_types() {
let _: Option<*mut c_void> = None;
let _: rfl_status = rfl_status::Ok;
}