Skip to main content

pvxs_sys/
bridge.rs

1// Copyright 2026 Tine Zata
2// SPDX-License-Identifier: MPL-2.0
3// bridge.rs - CXX bridge definition for Rust/C++ FFI
4// This defines the interface between Rust and C++
5
6#[cxx::bridge(namespace = "pvxs_wrapper")]
7mod ffi {
8
9    // Opaque C++ types - Rust sees these as opaque pointers
10
11    unsafe extern "C++" {
12        include!("wrapper.h");
13
14        // C++ types that Rust can hold but not inspect
15        type ContextWrapper;
16        type ValueWrapper;
17        #[cfg(feature = "async")]
18        type OperationWrapper; // Re-enabled for async operations
19
20        // Exception types for monitor events (C++ types, not Rust)
21        type MonitorConnected;
22        type MonitorDisconnected;
23        type MonitorFinished;
24        type MonitorRemoteError;
25        type MonitorClientError;
26
27        // Metadata structs (defined in C++ with std::optional)
28        type NTScalarAlarm;
29        type NTScalarTime;
30        type NTScalarDisplay;
31        type NTScalarControl;
32        type NTScalarValueAlarm;
33        type NTScalarMetadata;
34        type NTEnumMetadata;
35
36        // Metadata builder functions - construct metadata from Rust
37        fn create_alarm(severity: i32, status: i32, message: String) -> UniquePtr<NTScalarAlarm>;
38        fn create_time(
39            seconds_past_epoch: i64,
40            nanoseconds: i32,
41            user_tag: i32,
42        ) -> UniquePtr<NTScalarTime>;
43        fn create_display(
44            limit_low: i64,
45            limit_high: i64,
46            description: String,
47            units: String,
48            precision: i32,
49        ) -> UniquePtr<NTScalarDisplay>;
50        fn create_control(
51            limit_low: f64,
52            limit_high: f64,
53            min_step: f64,
54        ) -> UniquePtr<NTScalarControl>;
55        fn create_value_alarm(
56            active: bool,
57            low_alarm_limit: f64,
58            low_warning_limit: f64,
59            high_warning_limit: f64,
60            high_alarm_limit: f64,
61            low_alarm_severity: i32,
62            low_warning_severity: i32,
63            high_warning_severity: i32,
64            high_alarm_severity: i32,
65            hysteresis: u8,
66        ) -> UniquePtr<NTScalarValueAlarm>;
67
68        // Helper functions to build metadata with optional fields
69        fn create_metadata_no_optional(
70            alarm: &NTScalarAlarm,
71            time_stamp: &NTScalarTime,
72        ) -> UniquePtr<NTScalarMetadata>;
73        fn create_metadata_with_display(
74            alarm: &NTScalarAlarm,
75            time_stamp: &NTScalarTime,
76            display: &NTScalarDisplay,
77        ) -> UniquePtr<NTScalarMetadata>;
78        fn create_metadata_with_control(
79            alarm: &NTScalarAlarm,
80            time_stamp: &NTScalarTime,
81            control: &NTScalarControl,
82        ) -> UniquePtr<NTScalarMetadata>;
83        fn create_metadata_with_value_alarm(
84            alarm: &NTScalarAlarm,
85            time_stamp: &NTScalarTime,
86            value_alarm: &NTScalarValueAlarm,
87        ) -> UniquePtr<NTScalarMetadata>;
88        fn create_metadata_with_display_control(
89            alarm: &NTScalarAlarm,
90            time_stamp: &NTScalarTime,
91            display: &NTScalarDisplay,
92            control: &NTScalarControl,
93        ) -> UniquePtr<NTScalarMetadata>;
94        fn create_metadata_with_display_value_alarm(
95            alarm: &NTScalarAlarm,
96            time_stamp: &NTScalarTime,
97            display: &NTScalarDisplay,
98            value_alarm: &NTScalarValueAlarm,
99        ) -> UniquePtr<NTScalarMetadata>;
100        fn create_metadata_with_control_value_alarm(
101            alarm: &NTScalarAlarm,
102            time_stamp: &NTScalarTime,
103            control: &NTScalarControl,
104            value_alarm: &NTScalarValueAlarm,
105        ) -> UniquePtr<NTScalarMetadata>;
106        fn create_metadata_full(
107            alarm: &NTScalarAlarm,
108            time_stamp: &NTScalarTime,
109            display: &NTScalarDisplay,
110            control: &NTScalarControl,
111            value_alarm: &NTScalarValueAlarm,
112        ) -> UniquePtr<NTScalarMetadata>;
113
114        fn create_enum_metadata(
115            alarm: &NTScalarAlarm,
116            time_stamp: &NTScalarTime,
117        ) -> UniquePtr<NTEnumMetadata>;
118
119        // Logging control functions
120        fn pvxs_logger_config_env() -> Result<()>;
121        fn pvxs_logger_level_set(name: String, level: String) -> Result<()>;
122
123        // Note: RpcSourceWrapper - to be implemented later
124
125        // Context creation and operations
126        fn create_context_from_env() -> Result<UniquePtr<ContextWrapper>>;
127        fn context_get(
128            ctx: Pin<&mut ContextWrapper>,
129            pv_name: &str,
130            timeout: f64,
131        ) -> Result<UniquePtr<ValueWrapper>>;
132        fn context_put_double(
133            ctx: Pin<&mut ContextWrapper>,
134            pv_name: &str,
135            value: f64,
136            timeout: f64,
137        ) -> Result<()>;
138        fn context_put_int32(
139            ctx: Pin<&mut ContextWrapper>,
140            pv_name: &str,
141            value: i32,
142            timeout: f64,
143        ) -> Result<()>;
144        fn context_put_string(
145            ctx: Pin<&mut ContextWrapper>,
146            pv_name: &str,
147            value: String,
148            timeout: f64,
149        ) -> Result<()>;
150        fn context_put_enum(
151            ctx: Pin<&mut ContextWrapper>,
152            pv_name: &str,
153            value: i16,
154            timeout: f64,
155        ) -> Result<()>;
156        fn context_put_double_array(
157            ctx: Pin<&mut ContextWrapper>,
158            pv_name: &str,
159            value: Vec<f64>,
160            timeout: f64,
161        ) -> Result<()>;
162        fn context_put_int32_array(
163            ctx: Pin<&mut ContextWrapper>,
164            pv_name: &str,
165            value: Vec<i32>,
166            timeout: f64,
167        ) -> Result<()>;
168        fn context_put_string_array(
169            ctx: Pin<&mut ContextWrapper>,
170            pv_name: &str,
171            value: Vec<String>,
172            timeout: f64,
173        ) -> Result<()>;
174        fn context_info(
175            ctx: Pin<&mut ContextWrapper>,
176            pv_name: &str,
177            timeout: f64,
178        ) -> Result<UniquePtr<ValueWrapper>>;
179
180        // Value inspection
181        fn value_is_valid(val: &ValueWrapper) -> bool;
182        fn value_to_string(val: &ValueWrapper) -> String;
183        fn value_get_field_double(val: &ValueWrapper, field_name: String) -> Result<f64>;
184        fn value_get_field_int32(val: &ValueWrapper, field_name: String) -> Result<i32>;
185        fn value_get_field_string(val: &ValueWrapper, field_name: String) -> Result<String>;
186        fn value_get_field_enum(val: &ValueWrapper, field_name: String) -> Result<i16>;
187        fn value_get_field_double_array(val: &ValueWrapper, field_name: String)
188            -> Result<Vec<f64>>;
189        fn value_get_field_int32_array(val: &ValueWrapper, field_name: String) -> Result<Vec<i32>>;
190        fn value_get_field_string_array(
191            val: &ValueWrapper,
192            field_name: String,
193        ) -> Result<Vec<String>>;
194
195        // Monitor operations
196        fn context_monitor_create(
197            ctx: Pin<&mut ContextWrapper>,
198            pv_name: String,
199        ) -> Result<UniquePtr<MonitorWrapper>>;
200        fn monitor_start(monitor: Pin<&mut MonitorWrapper>) -> Result<()>;
201        fn monitor_stop(monitor: Pin<&mut MonitorWrapper>) -> Result<()>;
202        fn monitor_is_running(monitor: &MonitorWrapper) -> bool;
203        fn monitor_has_update(monitor: &MonitorWrapper) -> bool;
204        fn monitor_get_update(
205            monitor: Pin<&mut MonitorWrapper>,
206            timeout: f64,
207        ) -> Result<UniquePtr<ValueWrapper>>;
208        fn monitor_try_get_update(
209            monitor: Pin<&mut MonitorWrapper>,
210        ) -> Result<UniquePtr<ValueWrapper>>;
211        fn monitor_is_connected(monitor: &MonitorWrapper) -> bool;
212        fn monitor_get_name(monitor: &MonitorWrapper) -> String;
213        fn monitor_pop(monitor: Pin<&mut MonitorWrapper>) -> Result<UniquePtr<ValueWrapper>>;
214
215        // MonitorBuilder operations
216        fn context_monitor_builder_create(
217            ctx: Pin<&mut ContextWrapper>,
218            pv_name: String,
219        ) -> Result<UniquePtr<MonitorBuilderWrapper>>;
220        fn monitor_builder_mask_connected(
221            builder: Pin<&mut MonitorBuilderWrapper>,
222            mask: bool,
223        ) -> Result<()>;
224        fn monitor_builder_mask_disconnected(
225            builder: Pin<&mut MonitorBuilderWrapper>,
226            mask: bool,
227        ) -> Result<()>;
228        fn monitor_builder_set_event_callback(
229            builder: Pin<&mut MonitorBuilderWrapper>,
230            callback_ptr: usize,
231        ) -> Result<()>;
232        fn monitor_builder_exec(
233            builder: Pin<&mut MonitorBuilderWrapper>,
234        ) -> Result<UniquePtr<MonitorWrapper>>;
235        fn monitor_builder_exec_with_callback(
236            builder: Pin<&mut MonitorBuilderWrapper>,
237            callback_id: u64,
238        ) -> Result<UniquePtr<MonitorWrapper>>;
239
240        // Async operations using PVXS RPC (only available with async feature)
241        #[cfg(feature = "async")]
242        #[allow(dead_code)]
243        fn context_get_async(
244            ctx: Pin<&mut ContextWrapper>,
245            pv_name: &str,
246            timeout: f64,
247        ) -> Result<UniquePtr<OperationWrapper>>;
248
249        #[cfg(feature = "async")]
250        #[allow(dead_code)]
251        fn context_put_double_async(
252            ctx: Pin<&mut ContextWrapper>,
253            pv_name: &str,
254            value: f64,
255            timeout: f64,
256        ) -> Result<UniquePtr<OperationWrapper>>;
257
258        #[cfg(feature = "async")]
259        #[allow(dead_code)]
260        fn context_info_async(
261            ctx: Pin<&mut ContextWrapper>,
262            pv_name: &str,
263            timeout: f64,
264        ) -> Result<UniquePtr<OperationWrapper>>;
265
266        // Operation polling and completion (only available with async feature)
267        #[cfg(feature = "async")]
268        #[allow(dead_code)]
269        fn operation_is_done(op: &OperationWrapper) -> bool;
270        #[cfg(feature = "async")]
271        #[allow(dead_code)]
272        fn operation_get_result(op: Pin<&mut OperationWrapper>) -> Result<UniquePtr<ValueWrapper>>;
273        #[cfg(feature = "async")]
274        #[allow(dead_code)]
275        fn operation_cancel(op: Pin<&mut OperationWrapper>);
276        #[cfg(feature = "async")]
277        #[allow(dead_code)]
278        fn operation_wait_for_completion(op: Pin<&mut OperationWrapper>, timeout_ms: u64) -> bool;
279
280        // RPC operations
281        type RpcWrapper;
282        type MonitorWrapper;
283        type MonitorBuilderWrapper;
284
285        fn context_rpc_create(
286            ctx: Pin<&mut ContextWrapper>,
287            pv_name: String,
288        ) -> Result<UniquePtr<RpcWrapper>>;
289
290        fn rpc_arg_string(rpc: Pin<&mut RpcWrapper>, name: String, value: String) -> Result<()>;
291        fn rpc_arg_double(rpc: Pin<&mut RpcWrapper>, name: String, value: f64) -> Result<()>;
292        fn rpc_arg_int32(rpc: Pin<&mut RpcWrapper>, name: String, value: i32) -> Result<()>;
293        fn rpc_arg_bool(rpc: Pin<&mut RpcWrapper>, name: String, value: bool) -> Result<()>;
294
295        fn rpc_execute_sync(
296            rpc: Pin<&mut RpcWrapper>,
297            timeout: f64,
298        ) -> Result<UniquePtr<ValueWrapper>>;
299        #[cfg(feature = "async")]
300        #[allow(dead_code)]
301        fn rpc_execute_async(
302            rpc: Pin<&mut RpcWrapper>,
303            timeout: f64,
304        ) -> Result<UniquePtr<OperationWrapper>>;
305
306        // ====================================================================
307        // Server-side types and operations
308        // ====================================================================
309
310        // Server wrapper types
311        type ServerWrapper;
312        type SharedPVWrapper;
313        type StaticSourceWrapper;
314
315        // Server creation and management
316        fn server_create_from_env() -> Result<UniquePtr<ServerWrapper>>;
317        fn server_create_isolated() -> Result<UniquePtr<ServerWrapper>>;
318        fn server_start(server: Pin<&mut ServerWrapper>) -> Result<()>;
319        fn server_stop(server: Pin<&mut ServerWrapper>) -> Result<()>;
320        fn server_add_pv(
321            server: Pin<&mut ServerWrapper>,
322            name: String,
323            pv: Pin<&mut SharedPVWrapper>,
324        ) -> Result<()>;
325        fn server_remove_pv(server: Pin<&mut ServerWrapper>, name: String) -> Result<()>;
326        fn server_add_source(
327            server: Pin<&mut ServerWrapper>,
328            name: String,
329            source: Pin<&mut StaticSourceWrapper>,
330            order: i32,
331        ) -> Result<()>;
332        // Note: server_add_rpc_source - to be implemented later
333        fn server_get_tcp_port(server: &ServerWrapper) -> u16;
334        fn server_get_udp_port(server: &ServerWrapper) -> u16;
335
336        // SharedPV creation and operations
337        fn shared_pv_create_mailbox() -> Result<UniquePtr<SharedPVWrapper>>;
338        fn shared_pv_create_readonly() -> Result<UniquePtr<SharedPVWrapper>>;
339        fn shared_pv_open_double(
340            pv: Pin<&mut SharedPVWrapper>,
341            initial_value: f64,
342            metadata: &NTScalarMetadata,
343        ) -> Result<()>;
344        fn shared_pv_open_double_array(
345            pv: Pin<&mut SharedPVWrapper>,
346            initial_value: Vec<f64>,
347            metadata: &NTScalarMetadata,
348        ) -> Result<()>;
349        fn shared_pv_open_int32(
350            pv: Pin<&mut SharedPVWrapper>,
351            initial_value: i32,
352            metadata: &NTScalarMetadata,
353        ) -> Result<()>;
354        fn shared_pv_open_int32_array(
355            pv: Pin<&mut SharedPVWrapper>,
356            initial_value: Vec<i32>,
357            metadata: &NTScalarMetadata,
358        ) -> Result<()>;
359        fn shared_pv_open_string(
360            pv: Pin<&mut SharedPVWrapper>,
361            initial_value: String,
362            metadata: &NTScalarMetadata,
363        ) -> Result<()>;
364        fn shared_pv_open_string_array(
365            pv: Pin<&mut SharedPVWrapper>,
366            initial_value: Vec<String>,
367            metadata: &NTScalarMetadata,
368        ) -> Result<()>;
369        fn shared_pv_open_enum(
370            pv: Pin<&mut SharedPVWrapper>,
371            choices: Vec<String>,
372            selected_value: i16,
373            metadata: &NTEnumMetadata,
374        ) -> Result<()>;
375        fn shared_pv_is_open(pv: &SharedPVWrapper) -> bool;
376        fn shared_pv_close(pv: Pin<&mut SharedPVWrapper>) -> Result<()>;
377        fn shared_pv_post_double(pv: Pin<&mut SharedPVWrapper>, value: f64) -> Result<()>;
378        fn shared_pv_post_double_with_alarm(
379            pv: Pin<&mut SharedPVWrapper>,
380            value: f64,
381            severity: i32,
382            status: i32,
383            message: String,
384        ) -> Result<()>;
385        fn shared_pv_post_int32(pv: Pin<&mut SharedPVWrapper>, value: i32) -> Result<()>;
386        fn shared_pv_post_int32_with_alarm(
387            pv: Pin<&mut SharedPVWrapper>,
388            value: i32,
389            severity: i32,
390            status: i32,
391            message: String,
392        ) -> Result<()>;
393        fn shared_pv_post_string(pv: Pin<&mut SharedPVWrapper>, value: String) -> Result<()>;
394        fn shared_pv_post_enum(pv: Pin<&mut SharedPVWrapper>, value: i16) -> Result<()>;
395        fn shared_pv_post_enum_with_alarm(
396            pv: Pin<&mut SharedPVWrapper>,
397            value: i16,
398            severity: i32,
399            status: i32,
400            message: String,
401        ) -> Result<()>;
402        fn shared_pv_post_double_array(
403            pv: Pin<&mut SharedPVWrapper>,
404            value: Vec<f64>,
405        ) -> Result<()>;
406        fn shared_pv_post_int32_array(pv: Pin<&mut SharedPVWrapper>, value: Vec<i32>)
407            -> Result<()>;
408        fn shared_pv_post_string_array(
409            pv: Pin<&mut SharedPVWrapper>,
410            value: Vec<String>,
411        ) -> Result<()>;
412        fn shared_pv_fetch(pv: &SharedPVWrapper) -> Result<UniquePtr<ValueWrapper>>;
413
414        // StaticSource creation and operations
415        fn static_source_create() -> Result<UniquePtr<StaticSourceWrapper>>;
416        fn static_source_add_pv(
417            source: Pin<&mut StaticSourceWrapper>,
418            name: String,
419            pv: Pin<&mut SharedPVWrapper>,
420        ) -> Result<()>;
421        fn static_source_remove_pv(
422            source: Pin<&mut StaticSourceWrapper>,
423            name: String,
424        ) -> Result<()>;
425        fn static_source_close_all(source: Pin<&mut StaticSourceWrapper>) -> Result<()>;
426
427        // Note: RpcSource creation operations - to be implemented later
428    }
429}
430
431// Re-export the FFI types for use in the public API
432pub use ffi::*;