lmflow/ffi/graph/
input_poller.rs1#![allow(clippy::missing_safety_doc)]
2use super::*;
3
4#[no_mangle]
5pub unsafe extern "C" fn lmflow_graph_input(
6 g: *mut LMFlowGraph,
7 port: *const c_char,
8) -> *mut LMFlowInput {
9 guard_val(std::ptr::null_mut(), || {
10 let Some(slot) = slot_mut(g) else {
11 last_error::set("graph handle is null");
12 return std::ptr::null_mut();
13 };
14 let Some(gr) = slot.graph.as_ref() else {
15 last_error::set("graph not yet initialized");
16 return std::ptr::null_mut();
17 };
18 let Some(name) = cstr(port) else {
19 last_error::set("port name is null");
20 return std::ptr::null_mut();
21 };
22 let inner = gr.inner().clone();
23 match inner.input_edge_by_name(name) {
24 Some(edge) => {
25 Box::into_raw(Box::new(InputHandle { graph: inner, edge })) as *mut LMFlowInput
27 }
28 None => {
29 last_error::set(&format!("graph input port `{name}` does not exist"));
30 std::ptr::null_mut()
31 }
32 }
33 })
34}
35
36unsafe fn input_ref<'a>(i: *mut LMFlowInput) -> Option<&'a InputHandle> {
37 if i.is_null() {
38 None
39 } else {
40 Some(&*(i as *const InputHandle))
41 }
42}
43
44#[no_mangle]
45pub unsafe extern "C" fn lmflow_input_send(i: *mut LMFlowInput, pkt: LMFlowPacket) -> i32 {
46 guard(|| {
47 let p = take_packet(pkt);
48 match input_ref(i) {
49 Some(h) => to_status(h.graph.send_by_edge(h.edge, p, true)),
50 None => fail(Error::InvalidArg("input handle is null".into())),
51 }
52 })
53}
54
55#[no_mangle]
56pub unsafe extern "C" fn lmflow_input_try_send(i: *mut LMFlowInput, pkt: LMFlowPacket) -> i32 {
57 guard(|| {
58 let p = take_packet(pkt);
59 match input_ref(i) {
60 Some(h) => to_status(h.graph.send_by_edge(h.edge, p, false)),
61 None => fail(Error::InvalidArg("input handle is null".into())),
62 }
63 })
64}
65
66#[no_mangle]
67pub unsafe extern "C" fn lmflow_input_close(i: *mut LMFlowInput) {
68 guard_val((), || {
69 if let Some(h) = input_ref(i) {
70 h.graph.close_edge_pub(h.edge);
71 }
72 });
73}
74
75#[no_mangle]
76pub unsafe extern "C" fn lmflow_input_free(i: *mut LMFlowInput) {
77 guard_val((), || {
78 if !i.is_null() {
79 drop(Box::from_raw(i as *mut InputHandle));
81 }
82 });
83}
84
85#[no_mangle]
86pub unsafe extern "C" fn lmflow_graph_add_packet(
87 g: *mut LMFlowGraph,
88 port: *const c_char,
89 pkt: LMFlowPacket,
90) -> i32 {
91 guard(|| {
92 let p = take_packet(pkt);
93 let Some(name) = cstr(port) else {
94 return fail(Error::InvalidArg("port name is null".into()));
95 };
96 with_graph(g, |gr| {
97 let inner = gr.inner();
98 match inner.input_edge_by_name(name) {
99 Some(e) => to_status(inner.send_by_edge(e, p, true)),
100 None => fail(Error::NotFound(format!(
101 "graph input port `{name}` does not exist"
102 ))),
103 }
104 })
105 })
106}
107
108#[no_mangle]
109pub unsafe extern "C" fn lmflow_graph_close_input(g: *mut LMFlowGraph, port: *const c_char) -> i32 {
110 guard(|| {
111 let Some(name) = cstr(port) else {
112 return fail(Error::InvalidArg("port name is null".into()));
113 };
114 with_graph(g, |gr| to_status(gr.close_input(name)))
115 })
116}
117
118#[no_mangle]
119pub unsafe extern "C" fn lmflow_graph_close_all_inputs(g: *mut LMFlowGraph) {
120 guard_val((), || {
121 let _ = with_graph(g, |gr| {
122 gr.close_all_inputs();
123 code::OK
124 });
125 });
126}
127
128#[no_mangle]
129pub unsafe extern "C" fn lmflow_graph_add_poller(
130 g: *mut LMFlowGraph,
131 port: *const c_char,
132) -> *mut LMFlowPoller {
133 lmflow_graph_add_poller_ex(g, port, false)
134}
135
136#[no_mangle]
137pub unsafe extern "C" fn lmflow_graph_add_poller_ex(
138 g: *mut LMFlowGraph,
139 port: *const c_char,
140 observe_timestamp_bounds: bool,
141) -> *mut LMFlowPoller {
142 guard_val(std::ptr::null_mut(), || {
143 let Some(slot) = slot_mut(g) else {
144 last_error::set("graph handle is null");
145 return std::ptr::null_mut();
146 };
147 let Some(gr) = slot.graph.as_ref() else {
148 last_error::set("graph not yet initialized");
149 return std::ptr::null_mut();
150 };
151 let Some(name) = cstr(port) else {
152 last_error::set("port name is null");
153 return std::ptr::null_mut();
154 };
155 let poller = if observe_timestamp_bounds {
156 gr.add_poller_with_timestamp_bounds(name)
157 } else {
158 gr.add_poller(name)
159 };
160 match poller {
161 Ok(p) => {
162 Box::into_raw(Box::new(p)) as *mut LMFlowPoller
164 }
165 Err(e) => {
166 last_error::set(&e.to_string());
167 std::ptr::null_mut()
168 }
169 }
170 })
171}
172
173#[no_mangle]
174pub unsafe extern "C" fn lmflow_graph_add_poller_bounded(
175 g: *mut LMFlowGraph,
176 port: *const c_char,
177 capacity: usize,
178 overflow: i32,
179) -> *mut LMFlowPoller {
180 guard_val(std::ptr::null_mut(), || {
181 let Some(slot) = slot_mut(g) else {
182 last_error::set("graph handle is null");
183 return std::ptr::null_mut();
184 };
185 let Some(gr) = slot.graph.as_ref() else {
186 last_error::set("graph not yet initialized");
187 return std::ptr::null_mut();
188 };
189 let Some(name) = cstr(port) else {
190 last_error::set("port name is null");
191 return std::ptr::null_mut();
192 };
193 let overflow = match overflow {
194 0 => crate::graph::PollerOverflow::Block,
195 1 => crate::graph::PollerOverflow::DropOldest,
196 2 => crate::graph::PollerOverflow::DropNewest,
197 3 => crate::graph::PollerOverflow::Latest,
198 _ => {
199 last_error::set(
200 "unknown poller overflow policy (valid: BLOCK / DROP_OLDEST / DROP_NEWEST / LATEST)",
201 );
202 return std::ptr::null_mut();
203 }
204 };
205 match gr.add_poller_with_options(name, crate::graph::PollerOptions::new(capacity, overflow))
206 {
207 Ok(poller) => Box::into_raw(Box::new(poller)) as *mut LMFlowPoller,
208 Err(error) => {
209 last_error::set(&error.to_string());
210 std::ptr::null_mut()
211 }
212 }
213 })
214}
215
216unsafe fn poller_ref<'a>(p: *mut LMFlowPoller) -> Option<&'a Poller> {
217 if p.is_null() {
218 None
219 } else {
220 Some(&*(p as *const Poller))
221 }
222}
223
224#[no_mangle]
225pub unsafe extern "C" fn lmflow_poller_dropped_count(p: *mut LMFlowPoller) -> u64 {
226 guard_val(0, || poller_ref(p).map_or(0, Poller::dropped_count))
227}
228
229#[no_mangle]
230pub unsafe extern "C" fn lmflow_poller_next_status(
231 p: *mut LMFlowPoller,
232 out: *mut LMFlowPacket,
233) -> i32 {
234 guard(|| {
235 let Some(poller) = poller_ref(p) else {
236 return fail(Error::InvalidArg("poller handle is null".into()));
237 };
238 match poller.next_result() {
239 Ok(Some(pkt)) => {
240 if !out.is_null() {
241 *out = own_packet(pkt);
242 }
243 code::OK
244 }
245 Ok(None) => code::CLOSED,
246 Err(error) => fail(error),
247 }
248 })
249}
250
251#[no_mangle]
252pub unsafe extern "C" fn lmflow_poller_try_next_status(
253 p: *mut LMFlowPoller,
254 out: *mut LMFlowPacket,
255) -> i32 {
256 guard(|| {
257 let Some(poller) = poller_ref(p) else {
258 return fail(Error::InvalidArg("poller handle is null".into()));
259 };
260 match poller.try_next_result() {
261 Ok(Some(pkt)) => {
262 if !out.is_null() {
263 *out = own_packet(pkt);
264 }
265 code::OK
266 }
267 Ok(None) => {
268 if poller.is_closed() && poller.is_empty() {
279 code::CLOSED
280 } else {
281 code::WOULD_BLOCK
282 }
283 }
284 Err(error) => fail(error),
285 }
286 })
287}
288
289#[no_mangle]
290pub unsafe extern "C" fn lmflow_poller_next_timeout(
291 p: *mut LMFlowPoller,
292 out: *mut LMFlowPacket,
293 timeout_ms: i64,
294) -> i32 {
295 guard(|| {
296 let Some(poller) = poller_ref(p) else {
297 return fail(Error::InvalidArg("poller handle is null".into()));
298 };
299 match poller.next_timeout(std::time::Duration::from_millis(timeout_ms.max(0) as u64)) {
300 Ok(Some(pkt)) => {
301 if !out.is_null() {
302 *out = own_packet(pkt);
303 }
304 code::OK
305 }
306 Ok(None) => code::CLOSED,
307 Err(e) => fail(e),
308 }
309 })
310}
311
312#[no_mangle]
313pub unsafe extern "C" fn lmflow_poller_free(p: *mut LMFlowPoller) {
314 guard_val((), || {
315 if !p.is_null() {
316 drop(Box::from_raw(p as *mut Poller));
318 }
319 });
320}