Skip to main content

lmflow/ffi/graph/
lifecycle.rs

1#![allow(clippy::missing_safety_doc)]
2use super::*;
3
4#[no_mangle]
5pub extern "C" fn lmflow_graph_new() -> *mut LMFlowGraph {
6    guard_val(std::ptr::null_mut(), || {
7        // 此处只分配空槽,真正建图在 init_from_yaml。
8        // 顺便把错误状态清干净,免得调用方读到上一次遗留的 last_error。
9        last_error::set("");
10        Box::into_raw(Box::new(GraphSlot::default())) as *mut LMFlowGraph
11    })
12}
13
14/// `lmflow_graph_new` 先返回一个空槽,`init_from_yaml` 才真正建图。
15///
16/// 输入/输出句柄(`LMFlowInput*`/`LMFlowPoller*`)**不**由本槽持有 —— 它们是**调用方拥有**的:
17/// `lmflow_graph_input`/`lmflow_graph_add_poller` 返回一个独立的 `Box::into_raw` 句柄,
18/// 各自持一份 `Arc<GraphInner>`,须由调用方 `lmflow_input_free`/`lmflow_poller_free` 释放。
19/// 这样即使先 `lmflow_graph_free` 了图,句柄内存依旧有效(其 Arc 撑着引擎),
20/// 之后再用只会得到「图已结束」的错误,而不是 use-after-free。
21#[no_mangle]
22pub unsafe extern "C" fn lmflow_graph_free(g: *mut LMFlowGraph) {
23    guard_val((), || {
24        if g.is_null() {
25            return;
26        }
27        let slot = Box::from_raw(g as *mut GraphSlot);
28        if let Some(gr) = &slot.graph {
29            gr.cancel();
30            let _ = gr.wait_done();
31        }
32        drop(slot);
33    });
34}
35
36#[no_mangle]
37pub unsafe extern "C" fn lmflow_graph_init_from_yaml(
38    g: *mut LMFlowGraph,
39    yaml: *const c_char,
40) -> i32 {
41    guard(|| {
42        let Some(slot) = slot_mut(g) else {
43            return fail(Error::InvalidArg("graph handle is null".into()));
44        };
45        if slot.graph.is_some() {
46            return fail(Error::State("graph already initialized".into()));
47        }
48        let Some(text) = cstr(yaml) else {
49            return fail(Error::InvalidArg("yaml is empty or not UTF-8".into()));
50        };
51        match Graph::from_yaml(text) {
52            Ok(gr) => {
53                slot.graph = Some(gr);
54                code::OK
55            }
56            Err(e) => fail(e),
57        }
58    })
59}
60
61#[no_mangle]
62pub unsafe extern "C" fn lmflow_graph_init_from_yaml_file(
63    g: *mut LMFlowGraph,
64    path: *const c_char,
65) -> i32 {
66    guard(|| {
67        let Some(slot) = slot_mut(g) else {
68            return fail(Error::InvalidArg("graph handle is null".into()));
69        };
70        if slot.graph.is_some() {
71            return fail(Error::State("graph already initialized".into()));
72        }
73        let Some(p) = cstr(path) else {
74            return fail(Error::InvalidArg("path is null".into()));
75        };
76        match Graph::from_yaml_file(p) {
77            Ok(gr) => {
78                slot.graph = Some(gr);
79                code::OK
80            }
81            Err(e) => fail(e),
82        }
83    })
84}
85
86#[no_mangle]
87pub unsafe extern "C" fn lmflow_graph_start(g: *mut LMFlowGraph) -> i32 {
88    guard(|| with_graph(g, |gr| to_status(gr.start())))
89}
90
91/// 复位已结束的图,使其可再次 `start`,保留已 open 的算子实例(见 flow.h)。
92/// 图须处于 Terminated 且静止,否则返回 LMFLOW_ERR_STATE。
93#[no_mangle]
94pub unsafe extern "C" fn lmflow_graph_reset(g: *mut LMFlowGraph) -> i32 {
95    guard(|| with_graph(g, |gr| to_status(gr.reset())))
96}
97
98#[no_mangle]
99pub unsafe extern "C" fn lmflow_graph_set_side_packet(
100    g: *mut LMFlowGraph,
101    name: *const c_char,
102    pkt: LMFlowPacket,
103) -> i32 {
104    guard(|| {
105        let p = take_packet(pkt);
106        let Some(n) = cstr(name) else {
107            return fail(Error::InvalidArg("side packet name is null".into()));
108        };
109        with_graph(g, |gr| to_status(gr.set_side_packet(n, p)))
110    })
111}
112
113#[no_mangle]
114pub unsafe extern "C" fn lmflow_graph_cancel(g: *mut LMFlowGraph) {
115    guard_val((), || {
116        let _ = with_graph(g, |gr| {
117            gr.cancel();
118            code::OK
119        });
120    });
121}
122
123#[no_mangle]
124pub unsafe extern "C" fn lmflow_graph_wait_done(g: *mut LMFlowGraph) -> i32 {
125    guard(|| with_graph(g, |gr| to_status(gr.wait_done())))
126}
127
128#[no_mangle]
129pub unsafe extern "C" fn lmflow_graph_wait_done_timeout(g: *mut LMFlowGraph, ms: i64) -> i32 {
130    guard(|| {
131        with_graph(g, |gr| {
132            to_status(gr.wait_done_timeout(std::time::Duration::from_millis(ms.max(0) as u64)))
133        })
134    })
135}
136
137#[no_mangle]
138pub unsafe extern "C" fn lmflow_graph_wait_until_idle(g: *mut LMFlowGraph) -> i32 {
139    guard(|| with_graph(g, |gr| to_status(gr.wait_until_idle())))
140}
141
142#[no_mangle]
143pub unsafe extern "C" fn lmflow_graph_wait_until_idle_timeout(g: *mut LMFlowGraph, ms: i64) -> i32 {
144    guard(|| {
145        with_graph(g, |gr| {
146            to_status(
147                gr.wait_until_idle_timeout(std::time::Duration::from_millis(ms.max(0) as u64)),
148            )
149        })
150    })
151}
152
153#[no_mangle]
154pub unsafe extern "C" fn lmflow_graph_pump_step(g: *mut LMFlowGraph) -> bool {
155    guard_val(false, || {
156        let Some(slot) = slot_mut(g) else {
157            last_error::set("graph handle is null");
158            return false;
159        };
160        let Some(graph) = slot.graph.as_ref() else {
161            last_error::set("graph not yet initialized");
162            return false;
163        };
164        graph.pump_step()
165    })
166}
167
168#[no_mangle]
169pub unsafe extern "C" fn lmflow_graph_pump_steps(g: *mut LMFlowGraph, max_steps: usize) -> usize {
170    guard_val(0, || {
171        let Some(slot) = slot_mut(g) else {
172            last_error::set("graph handle is null");
173            return 0;
174        };
175        let Some(graph) = slot.graph.as_ref() else {
176            last_error::set("graph not yet initialized");
177            return 0;
178        };
179        graph.pump_steps(max_steps)
180    })
181}
182
183#[no_mangle]
184pub unsafe extern "C" fn lmflow_graph_set_wakeup_callback(
185    g: *mut LMFlowGraph,
186    cb: Option<unsafe extern "C" fn(*mut c_void)>,
187    user: *mut c_void,
188) -> i32 {
189    guard(|| {
190        with_graph(g, |graph| {
191            if let Some(callback) = cb {
192                let user = user as usize;
193                graph.set_wakeup_callback(move || unsafe { callback(user as *mut c_void) });
194            } else {
195                graph.clear_wakeup_callback();
196            }
197            code::OK
198        })
199    })
200}
201
202#[no_mangle]
203pub unsafe extern "C" fn lmflow_graph_pause(g: *mut LMFlowGraph) {
204    guard_val((), || {
205        if let Some(gr) = graph_of(g) {
206            gr.pause();
207        }
208    });
209}
210
211#[no_mangle]
212pub unsafe extern "C" fn lmflow_graph_resume(g: *mut LMFlowGraph) {
213    guard_val((), || {
214        if let Some(gr) = graph_of(g) {
215            gr.resume();
216        }
217    });
218}
219
220#[no_mangle]
221pub unsafe extern "C" fn lmflow_graph_last_error(g: *mut LMFlowGraph) -> *const c_char {
222    guard_val(c"".as_ptr(), || {
223        match slot_mut(g).and_then(|s| s.graph.as_ref()) {
224            Some(gr) => gr.inner().shared.error_cstr(),
225            None => c"".as_ptr(),
226        }
227    })
228}
229
230#[no_mangle]
231pub unsafe extern "C" fn lmflow_graph_state(g: *mut LMFlowGraph) -> i32 {
232    guard_val(0, || match slot_mut(g).and_then(|s| s.graph.as_ref()) {
233        Some(gr) => gr.state() as i32,
234        None => State::Created as i32,
235    })
236}
237
238// ---- 内省 ----