1use std::ffi::{CStr, CString};
2use std::os::raw::{c_char, c_int};
3use std::ptr;
4#[cfg(feature = "csharp")]
5use dotnet_bindgen;
6use crate::Parser;
7use crate::SemanticAnalyzer;
8use crate::HelixConfig as RustHelixConfig;
9use serde_json;
10#[repr(C)]
11pub struct HelixConfigFFI {
12 ptr: *mut RustHelixConfig,
13}
14#[cfg(feature = "csharp")]
15#[dotnet_bindgen]
16#[no_mangle]
17pub unsafe extern "C" fn helix_parse(
18 input: *const c_char,
19 error_code: *mut c_int,
20 error_message: *mut *mut c_char,
21) -> *mut HelixConfigFFI {
22 if input.is_null() {
23 *error_code = -1;
24 *error_message = CString::new("Input is null").unwrap().into_raw();
25 return ptr::null_mut();
26 }
27 let input_str = match CStr::from_ptr(input).to_str() {
28 Ok(s) => s,
29 Err(_) => {
30 *error_code = -2;
31 *error_message = CString::new("Invalid UTF-8 input").unwrap().into_raw();
32 return ptr::null_mut();
33 }
34 };
35 let mut parser = match Parser::new(input_str) {
36 Ok(p) => p,
37 Err(e) => {
38 *error_code = -3;
39 *error_message = CString::new(format!("Parser creation failed: {}", e))
40 .unwrap()
41 .into_raw();
42 return ptr::null_mut();
43 }
44 };
45 let ast = match parser.parse() {
46 Ok(a) => a,
47 Err(e) => {
48 *error_code = -4;
49 *error_message = CString::new(format!("Parse error: {}", e))
50 .unwrap()
51 .into_raw();
52 return ptr::null_mut();
53 }
54 };
55 let mut analyzer = SemanticAnalyzer::new();
56 let config = match analyzer.analyze(&ast) {
57 Ok(c) => c,
58 Err(e) => {
59 *error_code = -5;
60 *error_message = CString::new(format!("Semantic analysis failed: {}", e))
61 .unwrap()
62 .into_raw();
63 return ptr::null_mut();
64 }
65 };
66 *error_code = 0;
67 *error_message = ptr::null_mut();
68 let ffi_config = Box::new(HelixConfigFFI {
69 ptr: Box::into_raw(Box::new(config)),
70 });
71 Box::into_raw(ffi_config)
72}
73#[cfg(feature = "csharp")]
74#[dotnet_bindgen]
75#[no_mangle]
76pub unsafe extern "C" fn helix_free_config(config: *mut HelixConfigFFI) {
77 if config.is_null() {
78 return;
79 }
80 let ffi_config = Box::from_raw(config);
81 if !ffi_config.ptr.is_null() {
82 let _ = Box::from_raw(ffi_config.ptr);
83 }
84}
85#[cfg(feature = "csharp")]
86#[dotnet_bindgen]
87#[no_mangle]
88pub unsafe extern "C" fn helix_free_string(s: *mut c_char) {
89 if !s.is_null() {
90 let _ = CString::from_raw(s);
91 }
92}
93#[cfg(feature = "csharp")]
94#[dotnet_bindgen]
95#[no_mangle]
96pub unsafe extern "C" fn helix_config_get_agents(
97 config: *const HelixConfigFFI,
98) -> *mut c_char {
99 if config.is_null() {
100 return ptr::null_mut();
101 }
102 let ffi_config = &*config;
103 if ffi_config.ptr.is_null() {
104 return ptr::null_mut();
105 }
106 let rust_config = &*ffi_config.ptr;
107 let agents_json = serde_json::to_string(&rust_config.agents)
108 .unwrap_or_else(|_| "{}".to_string());
109 CString::new(agents_json).unwrap().into_raw()
110}
111#[cfg(feature = "csharp")]
112#[dotnet_bindgen]
113#[no_mangle]
114pub unsafe extern "C" fn helix_config_get_workflows(
115 config: *const HelixConfigFFI,
116) -> *mut c_char {
117 if config.is_null() {
118 return ptr::null_mut();
119 }
120 let ffi_config = &*config;
121 if ffi_config.ptr.is_null() {
122 return ptr::null_mut();
123 }
124 let rust_config = &*ffi_config.ptr;
125 let workflows_json = serde_json::to_string(&rust_config.workflows)
126 .unwrap_or_else(|_| "{}".to_string());
127 CString::new(workflows_json).unwrap().into_raw()
128}
129#[cfg(feature = "csharp")]
130#[dotnet_bindgen]
131#[no_mangle]
132pub unsafe extern "C" fn helix_config_get_memories(
133 config: *const HelixConfigFFI,
134) -> *mut c_char {
135 if config.is_null() {
136 return ptr::null_mut();
137 }
138 let ffi_config = &*config;
139 if ffi_config.ptr.is_null() {
140 return ptr::null_mut();
141 }
142 let rust_config = &*ffi_config.ptr;
143 let memories_json = serde_json::to_string(&rust_config.memories)
144 .unwrap_or_else(|_| "{}".to_string());
145 CString::new(memories_json).unwrap().into_raw()
146}
147#[cfg(feature = "csharp")]
148#[dotnet_bindgen]
149#[no_mangle]
150pub unsafe extern "C" fn helix_config_get_contexts(
151 config: *const HelixConfigFFI,
152) -> *mut c_char {
153 if config.is_null() {
154 return ptr::null_mut();
155 }
156 let ffi_config = &*config;
157 if ffi_config.ptr.is_null() {
158 return ptr::null_mut();
159 }
160 let rust_config = &*ffi_config.ptr;
161 let contexts_json = serde_json::to_string(&rust_config.contexts)
162 .unwrap_or_else(|_| "{}".to_string());
163 CString::new(contexts_json).unwrap().into_raw()
164}
165#[cfg(feature = "csharp")]
166#[dotnet_bindgen]
167#[no_mangle]
168pub unsafe extern "C" fn helix_config_get_crews(
169 config: *const HelixConfigFFI,
170) -> *mut c_char {
171 if config.is_null() {
172 return ptr::null_mut();
173 }
174 let ffi_config = &*config;
175 if ffi_config.ptr.is_null() {
176 return ptr::null_mut();
177 }
178 let rust_config = &*ffi_config.ptr;
179 let crews_json = serde_json::to_string(&rust_config.crews)
180 .unwrap_or_else(|_| "{}".to_string());
181 CString::new(crews_json).unwrap().into_raw()
182}
183#[cfg(feature = "csharp")]
184#[dotnet_bindgen]
185#[no_mangle]
186pub unsafe extern "C" fn helix_config_get_pipelines(
187 config: *const HelixConfigFFI,
188) -> *mut c_char {
189 if config.is_null() {
190 return ptr::null_mut();
191 }
192 let ffi_config = &*config;
193 if ffi_config.ptr.is_null() {
194 return ptr::null_mut();
195 }
196 let rust_config = &*ffi_config.ptr;
197 let pipelines_json = serde_json::to_string(&rust_config.pipelines)
198 .unwrap_or_else(|_| "{}".to_string());
199 CString::new(pipelines_json).unwrap().into_raw()
200}
201#[cfg(feature = "csharp")]
202#[dotnet_bindgen]
203#[no_mangle]
204pub unsafe extern "C" fn helix_config_get_agent(
205 config: *const HelixConfigFFI,
206 name: *const c_char,
207) -> *mut c_char {
208 if config.is_null() || name.is_null() {
209 return ptr::null_mut();
210 }
211 let ffi_config = &*config;
212 if ffi_config.ptr.is_null() {
213 return ptr::null_mut();
214 }
215 let name_str = match CStr::from_ptr(name).to_str() {
216 Ok(s) => s,
217 Err(_) => return ptr::null_mut(),
218 };
219 let rust_config = &*ffi_config.ptr;
220 if let Some(agent) = rust_config.agents.get(name_str) {
221 let agent_json = serde_json::to_string(agent)
222 .unwrap_or_else(|_| "{}".to_string());
223 CString::new(agent_json).unwrap().into_raw()
224 } else {
225 ptr::null_mut()
226 }
227}
228#[cfg(feature = "csharp")]
229#[dotnet_bindgen]
230#[no_mangle]
231pub unsafe extern "C" fn helix_config_get_workflow(
232 config: *const HelixConfigFFI,
233 name: *const c_char,
234) -> *mut c_char {
235 if config.is_null() || name.is_null() {
236 return ptr::null_mut();
237 }
238 let ffi_config = &*config;
239 if ffi_config.ptr.is_null() {
240 return ptr::null_mut();
241 }
242 let name_str = match CStr::from_ptr(name).to_str() {
243 Ok(s) => s,
244 Err(_) => return ptr::null_mut(),
245 };
246 let rust_config = &*ffi_config.ptr;
247 if let Some(workflow) = rust_config.workflows.get(name_str) {
248 let workflow_json = serde_json::to_string(workflow)
249 .unwrap_or_else(|_| "{}".to_string());
250 CString::new(workflow_json).unwrap().into_raw()
251 } else {
252 ptr::null_mut()
253 }
254}