use std::ffi::CStr;
use std::ffi::CString;
use std::os::raw::c_char;
use std::os::raw::c_int;
use crate::symbolic::core::Expr;
use crate::symbolic::graph::Graph;
use crate::symbolic::graph_algorithms::bfs;
use crate::symbolic::graph_algorithms::connected_components;
use crate::symbolic::graph_algorithms::dfs;
use crate::symbolic::graph_algorithms::edmonds_karp_max_flow;
use crate::symbolic::graph_algorithms::has_cycle;
use crate::symbolic::graph_algorithms::is_bipartite;
use crate::symbolic::graph_algorithms::kruskal_mst;
#[repr(C)]
pub struct RssnGraph {
_private: [u8; 0],
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_new(is_directed: c_int) -> *mut RssnGraph {
let graph = Graph::<String>::new(is_directed != 0);
Box::into_raw(Box::new(graph)).cast::<RssnGraph>()
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_free(ptr: *mut RssnGraph) {
if !ptr.is_null() {
unsafe {
drop(Box::from_raw(ptr.cast::<Graph<String>>()));
};
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_add_node(
ptr: *mut RssnGraph,
label: *const c_char,
) -> usize {
if ptr.is_null() || label.is_null() {
return usize::MAX;
}
let graph = unsafe { &mut *ptr.cast::<Graph<String>>() };
let label_str = unsafe { CStr::from_ptr(label).to_string_lossy().into_owned() };
graph.add_node(label_str)
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_add_edge(
ptr: *mut RssnGraph,
from_label: *const c_char,
to_label: *const c_char,
weight: *const Expr,
) {
if ptr.is_null() || from_label.is_null() || to_label.is_null() || weight.is_null() {
return;
}
let graph = unsafe { &mut *ptr.cast::<Graph<String>>() };
let from = unsafe { CStr::from_ptr(from_label).to_string_lossy().into_owned() };
let to = unsafe { CStr::from_ptr(to_label).to_string_lossy().into_owned() };
let weight_expr = unsafe { (*weight).clone() };
graph.add_edge(&from, &to, weight_expr);
}
#[unsafe(no_mangle)]
pub const extern "C" fn rssn_graph_node_count(ptr: *const RssnGraph) -> usize {
if ptr.is_null() {
return 0;
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
graph.node_count()
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_adjacency_matrix(ptr: *const RssnGraph) -> *mut Expr {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
Box::into_raw(Box::new(graph.to_adjacency_matrix()))
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_incidence_matrix(ptr: *const RssnGraph) -> *mut Expr {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
Box::into_raw(Box::new(graph.to_incidence_matrix()))
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_laplacian_matrix(ptr: *const RssnGraph) -> *mut Expr {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
Box::into_raw(Box::new(graph.to_laplacian_matrix()))
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_bfs(
ptr: *const RssnGraph,
start_node: usize,
) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
let result = bfs(graph, start_node);
match serde_json::to_string(&result) {
| Ok(json) => CString::new(json).unwrap().into_raw(),
| Err(_) => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_dfs(
ptr: *const RssnGraph,
start_node: usize,
) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
let result = dfs(graph, start_node);
match serde_json::to_string(&result) {
| Ok(json) => CString::new(json).unwrap().into_raw(),
| Err(_) => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_connected_components(ptr: *const RssnGraph) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
let result = connected_components(graph);
match serde_json::to_string(&result) {
| Ok(json) => CString::new(json).unwrap().into_raw(),
| Err(_) => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_max_flow(
ptr: *const RssnGraph,
source: usize,
sink: usize,
) -> f64 {
if ptr.is_null() {
return 0.0;
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
edmonds_karp_max_flow(graph, source, sink)
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_kruskal_mst(ptr: *const RssnGraph) -> *mut c_char {
if ptr.is_null() {
return std::ptr::null_mut();
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
let mst = kruskal_mst(graph);
let edges: Vec<(usize, usize, String)> = mst
.iter()
.map(|(u, v, w)| (*u, *v, format!("{w}")))
.collect();
match serde_json::to_string(&edges) {
| Ok(json) => CString::new(json).unwrap().into_raw(),
| Err(_) => std::ptr::null_mut(),
}
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_has_cycle(ptr: *const RssnGraph) -> c_int {
if ptr.is_null() {
return 0;
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
i32::from(has_cycle(graph))
}
#[unsafe(no_mangle)]
pub extern "C" fn rssn_graph_is_bipartite(ptr: *const RssnGraph) -> c_int {
if ptr.is_null() {
return 0;
}
let graph = unsafe { &*ptr.cast::<Graph<String>>() };
i32::from(is_bipartite(graph).is_some())
}