agentic_codebase/ffi/
c_api.rs1use std::ffi::CStr;
7use std::os::raw::c_char;
8use std::path::Path;
9
10use crate::format::AcbReader;
11use crate::graph::CodeGraph;
12
13pub const ACB_OK: i32 = 0;
19pub const ACB_ERR_IO: i32 = -1;
21pub const ACB_ERR_INVALID: i32 = -2;
23pub const ACB_ERR_NOT_FOUND: i32 = -3;
25pub const ACB_ERR_OVERFLOW: i32 = -4;
27pub const ACB_ERR_NULL_PTR: i32 = -5;
29
30#[no_mangle]
40pub unsafe extern "C" fn acb_graph_open(path: *const c_char) -> *mut std::ffi::c_void {
41 std::panic::catch_unwind(|| {
42 if path.is_null() {
43 return std::ptr::null_mut();
44 }
45 let path_str = unsafe { CStr::from_ptr(path) };
46 let path_str = match path_str.to_str() {
47 Ok(s) => s,
48 Err(_) => return std::ptr::null_mut(),
49 };
50 match AcbReader::read_from_file(Path::new(path_str)) {
51 Ok(graph) => Box::into_raw(Box::new(graph)) as *mut std::ffi::c_void,
52 Err(_) => std::ptr::null_mut(),
53 }
54 })
55 .unwrap_or(std::ptr::null_mut())
56}
57
58#[no_mangle]
65pub unsafe extern "C" fn acb_graph_free(graph: *mut std::ffi::c_void) {
66 if !graph.is_null() {
67 let _ = std::panic::catch_unwind(|| unsafe {
68 drop(Box::from_raw(graph as *mut CodeGraph));
69 });
70 }
71}
72
73#[no_mangle]
83pub unsafe extern "C" fn acb_graph_unit_count(graph: *mut std::ffi::c_void) -> u64 {
84 std::panic::catch_unwind(|| {
85 if graph.is_null() {
86 return 0;
87 }
88 let graph = unsafe { &*(graph as *const CodeGraph) };
89 graph.unit_count() as u64
90 })
91 .unwrap_or(0)
92}
93
94#[no_mangle]
100pub unsafe extern "C" fn acb_graph_edge_count(graph: *mut std::ffi::c_void) -> u64 {
101 std::panic::catch_unwind(|| {
102 if graph.is_null() {
103 return 0;
104 }
105 let graph = unsafe { &*(graph as *const CodeGraph) };
106 graph.edge_count() as u64
107 })
108 .unwrap_or(0)
109}
110
111#[no_mangle]
117pub unsafe extern "C" fn acb_graph_dimension(graph: *mut std::ffi::c_void) -> u32 {
118 std::panic::catch_unwind(|| {
119 if graph.is_null() {
120 return 0;
121 }
122 let graph = unsafe { &*(graph as *const CodeGraph) };
123 graph.dimension() as u32
124 })
125 .unwrap_or(0)
126}
127
128#[no_mangle]
139pub unsafe extern "C" fn acb_graph_get_unit_name(
140 graph: *mut std::ffi::c_void,
141 unit_id: u64,
142 buffer: *mut c_char,
143 buffer_size: u32,
144) -> i32 {
145 std::panic::catch_unwind(|| {
146 if graph.is_null() || buffer.is_null() {
147 return ACB_ERR_NULL_PTR;
148 }
149 let graph = unsafe { &*(graph as *const CodeGraph) };
150 match graph.get_unit(unit_id) {
151 Some(unit) => {
152 let name_bytes = unit.name.as_bytes();
153 if name_bytes.len() + 1 > buffer_size as usize {
154 return ACB_ERR_OVERFLOW;
155 }
156 unsafe {
157 std::ptr::copy_nonoverlapping(
158 name_bytes.as_ptr(),
159 buffer as *mut u8,
160 name_bytes.len(),
161 );
162 *buffer.add(name_bytes.len()) = 0; }
164 name_bytes.len() as i32
165 }
166 None => ACB_ERR_NOT_FOUND,
167 }
168 })
169 .unwrap_or(ACB_ERR_INVALID)
170}
171
172#[no_mangle]
178pub unsafe extern "C" fn acb_graph_get_unit_type(
179 graph: *mut std::ffi::c_void,
180 unit_id: u64,
181) -> i32 {
182 std::panic::catch_unwind(|| {
183 if graph.is_null() {
184 return -1;
185 }
186 let graph = unsafe { &*(graph as *const CodeGraph) };
187 graph
188 .get_unit(unit_id)
189 .map(|u| u.unit_type as i32)
190 .unwrap_or(-1)
191 })
192 .unwrap_or(-1)
193}
194
195#[no_mangle]
202pub unsafe extern "C" fn acb_graph_get_unit_file(
203 graph: *mut std::ffi::c_void,
204 unit_id: u64,
205 buffer: *mut c_char,
206 buffer_size: u32,
207) -> i32 {
208 std::panic::catch_unwind(|| {
209 if graph.is_null() || buffer.is_null() {
210 return ACB_ERR_NULL_PTR;
211 }
212 let graph = unsafe { &*(graph as *const CodeGraph) };
213 match graph.get_unit(unit_id) {
214 Some(unit) => {
215 let path_str = unit.file_path.display().to_string();
216 let path_bytes = path_str.as_bytes();
217 if path_bytes.len() + 1 > buffer_size as usize {
218 return ACB_ERR_OVERFLOW;
219 }
220 unsafe {
221 std::ptr::copy_nonoverlapping(
222 path_bytes.as_ptr(),
223 buffer as *mut u8,
224 path_bytes.len(),
225 );
226 *buffer.add(path_bytes.len()) = 0;
227 }
228 path_bytes.len() as i32
229 }
230 None => ACB_ERR_NOT_FOUND,
231 }
232 })
233 .unwrap_or(ACB_ERR_INVALID)
234}
235
236#[no_mangle]
242pub unsafe extern "C" fn acb_graph_get_unit_complexity(
243 graph: *mut std::ffi::c_void,
244 unit_id: u64,
245) -> f32 {
246 std::panic::catch_unwind(|| {
247 if graph.is_null() {
248 return -1.0;
249 }
250 let graph = unsafe { &*(graph as *const CodeGraph) };
251 graph
252 .get_unit(unit_id)
253 .map(|u| u.complexity as f32)
254 .unwrap_or(-1.0)
255 })
256 .unwrap_or(-1.0)
257}
258
259#[no_mangle]
270pub unsafe extern "C" fn acb_graph_get_edges(
271 graph: *mut std::ffi::c_void,
272 unit_id: u64,
273 target_ids: *mut u64,
274 edge_types: *mut u8,
275 weights: *mut f32,
276 max_edges: u32,
277) -> i32 {
278 std::panic::catch_unwind(|| {
279 if graph.is_null() || target_ids.is_null() || edge_types.is_null() || weights.is_null() {
280 return ACB_ERR_NULL_PTR;
281 }
282 let graph = unsafe { &*(graph as *const CodeGraph) };
283 let edges = graph.edges_from(unit_id);
284 let count = edges.len().min(max_edges as usize);
285 for (i, edge) in edges.iter().take(count).enumerate() {
286 unsafe {
287 *target_ids.add(i) = edge.target_id;
288 *edge_types.add(i) = edge.edge_type as u8;
289 *weights.add(i) = edge.weight;
290 }
291 }
292 count as i32
293 })
294 .unwrap_or(ACB_ERR_INVALID)
295}
296
297#[no_mangle]
303pub unsafe extern "C" fn acb_graph_get_unit_language(
304 graph: *mut std::ffi::c_void,
305 unit_id: u64,
306) -> i32 {
307 std::panic::catch_unwind(|| {
308 if graph.is_null() {
309 return -1;
310 }
311 let graph = unsafe { &*(graph as *const CodeGraph) };
312 graph
313 .get_unit(unit_id)
314 .map(|u| u.language as i32)
315 .unwrap_or(-1)
316 })
317 .unwrap_or(-1)
318}
319
320#[no_mangle]
326pub unsafe extern "C" fn acb_graph_get_unit_stability(
327 graph: *mut std::ffi::c_void,
328 unit_id: u64,
329) -> f32 {
330 std::panic::catch_unwind(|| {
331 if graph.is_null() {
332 return -1.0;
333 }
334 let graph = unsafe { &*(graph as *const CodeGraph) };
335 graph
336 .get_unit(unit_id)
337 .map(|u| u.stability_score)
338 .unwrap_or(-1.0)
339 })
340 .unwrap_or(-1.0)
341}