1#![allow(clippy::missing_safety_doc)]
2
3use crate::EipClient;
4use crate::PlcValue;
5use crate::RUNTIME;
6use lazy_static::lazy_static;
7use std::collections::HashMap;
8use std::ffi::{CStr, CString};
9use std::os::raw::{c_char, c_int};
10use std::ptr;
11use std::sync::Mutex;
12
13lazy_static! {
15 static ref FFI_CLIENTS: Mutex<HashMap<i32, EipClient>> = Mutex::new(HashMap::new());
16 static ref FFI_NEXT_ID: Mutex<i32> = Mutex::new(1);
17}
18
19#[no_mangle]
28pub unsafe extern "C" fn eip_connect(ip_address: *const c_char) -> c_int {
29 if ip_address.is_null() {
30 return -1;
31 }
32
33 let ip_str = match unsafe { CStr::from_ptr(ip_address) }.to_str() {
34 Ok(s) => s,
35 Err(_) => return -1,
36 };
37
38 let client = match RUNTIME.block_on(EipClient::new(ip_str)) {
39 Ok(client) => client,
40 Err(_) => return -1,
41 };
42
43 let client_id = {
44 let mut next_id = FFI_NEXT_ID.lock().unwrap();
45 let id = *next_id;
46 *next_id += 1;
47 id
48 };
49
50 {
51 let mut clients = FFI_CLIENTS.lock().unwrap();
52 clients.insert(client_id, client);
53 }
54
55 client_id
56}
57
58#[no_mangle]
66pub unsafe extern "C" fn eip_disconnect(client_id: c_int) -> c_int {
67 let mut clients = FFI_CLIENTS.lock().unwrap();
68 match clients.remove(&client_id) {
69 Some(_) => 0,
70 None => -1,
71 }
72}
73
74#[no_mangle]
84pub unsafe extern "C" fn eip_read_bool(
85 client_id: c_int,
86 tag_name: *const c_char,
87 result: *mut c_int,
88) -> c_int {
89 if tag_name.is_null() || result.is_null() {
90 return -1;
91 }
92
93 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
94 Ok(s) => s,
95 Err(_) => return -1,
96 };
97
98 let mut clients = FFI_CLIENTS.lock().unwrap();
99 match clients.get_mut(&client_id) {
100 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
101 Ok(PlcValue::Bool(value)) => {
102 unsafe {
103 *result = if value { 1 } else { 0 };
104 }
105 0
106 }
107 _ => -1,
108 },
109 None => -1,
110 }
111}
112
113#[no_mangle]
123pub unsafe extern "C" fn eip_write_bool(
124 client_id: c_int,
125 tag_name: *const c_char,
126 value: c_int,
127) -> c_int {
128 if tag_name.is_null() {
129 return -1;
130 }
131
132 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
133 Ok(s) => s,
134 Err(_) => return -1,
135 };
136
137 let mut clients = FFI_CLIENTS.lock().unwrap();
138 match clients.get_mut(&client_id) {
139 Some(client) => {
140 let bool_value = value != 0;
141 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Bool(bool_value))) {
142 Ok(_) => 0,
143 Err(_) => -1,
144 }
145 }
146 None => -1,
147 }
148}
149
150#[no_mangle]
161pub unsafe extern "C" fn eip_read_sint(
162 client_id: c_int,
163 tag_name: *const c_char,
164 result: *mut i8,
165) -> c_int {
166 if tag_name.is_null() || result.is_null() {
167 return -1;
168 }
169
170 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
171 Ok(s) => s,
172 Err(_) => return -1,
173 };
174
175 let mut clients = FFI_CLIENTS.lock().unwrap();
176 match clients.get_mut(&client_id) {
177 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
178 Ok(PlcValue::Sint(value)) => {
179 unsafe {
180 *result = value;
181 }
182 0
183 }
184 _ => -1,
185 },
186 None => -1,
187 }
188}
189
190#[no_mangle]
199pub unsafe extern "C" fn eip_write_sint(
200 client_id: c_int,
201 tag_name: *const c_char,
202 value: i8,
203) -> c_int {
204 if tag_name.is_null() {
205 return -1;
206 }
207
208 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
209 Ok(s) => s,
210 Err(_) => return -1,
211 };
212
213 let mut clients = FFI_CLIENTS.lock().unwrap();
214 match clients.get_mut(&client_id) {
215 Some(client) => {
216 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Sint(value))) {
217 Ok(_) => 0,
218 Err(_) => -1,
219 }
220 }
221 None => -1,
222 }
223}
224
225#[no_mangle]
227pub unsafe extern "C" fn eip_read_int(
228 client_id: c_int,
229 tag_name: *const c_char,
230 result: *mut i16,
231) -> c_int {
232 if tag_name.is_null() || result.is_null() {
233 return -1;
234 }
235
236 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
237 Ok(s) => s,
238 Err(_) => return -1,
239 };
240
241 let mut clients = FFI_CLIENTS.lock().unwrap();
242 match clients.get_mut(&client_id) {
243 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
244 Ok(PlcValue::Int(value)) => {
245 unsafe {
246 *result = value;
247 }
248 0
249 }
250 _ => -1,
251 },
252 None => -1,
253 }
254}
255
256#[no_mangle]
257pub unsafe extern "C" fn eip_write_int(
258 client_id: c_int,
259 tag_name: *const c_char,
260 value: i16,
261) -> c_int {
262 if tag_name.is_null() {
263 return -1;
264 }
265
266 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
267 Ok(s) => s,
268 Err(_) => return -1,
269 };
270
271 let mut clients = FFI_CLIENTS.lock().unwrap();
272 match clients.get_mut(&client_id) {
273 Some(client) => {
274 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Int(value))) {
275 Ok(_) => 0,
276 Err(_) => -1,
277 }
278 }
279 None => -1,
280 }
281}
282
283#[no_mangle]
285pub unsafe extern "C" fn eip_read_dint(
286 client_id: c_int,
287 tag_name: *const c_char,
288 result: *mut c_int,
289) -> c_int {
290 if tag_name.is_null() || result.is_null() {
291 return -1;
292 }
293
294 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
295 Ok(s) => s,
296 Err(_) => return -1,
297 };
298
299 let mut clients = FFI_CLIENTS.lock().unwrap();
300 match clients.get_mut(&client_id) {
301 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
302 Ok(PlcValue::Dint(value)) => {
303 unsafe {
304 *result = value;
305 }
306 0
307 }
308 _ => -1,
309 },
310 None => -1,
311 }
312}
313
314#[no_mangle]
316pub unsafe extern "C" fn eip_write_dint(
317 client_id: c_int,
318 tag_name: *const c_char,
319 value: c_int,
320) -> c_int {
321 if tag_name.is_null() {
322 return -1;
323 }
324
325 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
326 Ok(s) => s,
327 Err(_) => return -1,
328 };
329
330 let mut clients = FFI_CLIENTS.lock().unwrap();
331 match clients.get_mut(&client_id) {
332 Some(client) => {
333 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Dint(value))) {
334 Ok(_) => 0,
335 Err(_) => -1,
336 }
337 }
338 None => -1,
339 }
340}
341
342#[no_mangle]
344pub unsafe extern "C" fn eip_read_lint(
345 client_id: c_int,
346 tag_name: *const c_char,
347 result: *mut i64,
348) -> c_int {
349 if tag_name.is_null() || result.is_null() {
350 return -1;
351 }
352
353 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
354 Ok(s) => s,
355 Err(_) => return -1,
356 };
357
358 let mut clients = FFI_CLIENTS.lock().unwrap();
359 match clients.get_mut(&client_id) {
360 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
361 Ok(PlcValue::Lint(value)) => {
362 unsafe {
363 *result = value;
364 }
365 0
366 }
367 _ => -1,
368 },
369 None => -1,
370 }
371}
372
373#[no_mangle]
374pub unsafe extern "C" fn eip_write_lint(
375 client_id: c_int,
376 tag_name: *const c_char,
377 value: i64,
378) -> c_int {
379 if tag_name.is_null() {
380 return -1;
381 }
382
383 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
384 Ok(s) => s,
385 Err(_) => return -1,
386 };
387
388 let mut clients = FFI_CLIENTS.lock().unwrap();
389 match clients.get_mut(&client_id) {
390 Some(client) => {
391 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Lint(value))) {
392 Ok(_) => 0,
393 Err(_) => -1,
394 }
395 }
396 None => -1,
397 }
398}
399
400#[no_mangle]
402pub unsafe extern "C" fn eip_read_usint(
403 client_id: c_int,
404 tag_name: *const c_char,
405 result: *mut u8,
406) -> c_int {
407 if tag_name.is_null() || result.is_null() {
408 return -1;
409 }
410
411 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
412 Ok(s) => s,
413 Err(_) => return -1,
414 };
415
416 let mut clients = FFI_CLIENTS.lock().unwrap();
417 match clients.get_mut(&client_id) {
418 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
419 Ok(PlcValue::Usint(value)) => {
420 unsafe {
421 *result = value;
422 }
423 0
424 }
425 _ => -1,
426 },
427 None => -1,
428 }
429}
430
431#[no_mangle]
432pub unsafe extern "C" fn eip_write_usint(
433 client_id: c_int,
434 tag_name: *const c_char,
435 value: u8,
436) -> c_int {
437 if tag_name.is_null() {
438 return -1;
439 }
440
441 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
442 Ok(s) => s,
443 Err(_) => return -1,
444 };
445
446 let mut clients = FFI_CLIENTS.lock().unwrap();
447 match clients.get_mut(&client_id) {
448 Some(client) => {
449 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Usint(value))) {
450 Ok(_) => 0,
451 Err(_) => -1,
452 }
453 }
454 None => -1,
455 }
456}
457
458#[no_mangle]
460pub unsafe extern "C" fn eip_read_uint(
461 client_id: c_int,
462 tag_name: *const c_char,
463 result: *mut u16,
464) -> c_int {
465 if tag_name.is_null() || result.is_null() {
466 return -1;
467 }
468
469 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
470 Ok(s) => s,
471 Err(_) => return -1,
472 };
473
474 let mut clients = FFI_CLIENTS.lock().unwrap();
475 match clients.get_mut(&client_id) {
476 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
477 Ok(PlcValue::Uint(value)) => {
478 unsafe {
479 *result = value;
480 }
481 0
482 }
483 _ => -1,
484 },
485 None => -1,
486 }
487}
488
489#[no_mangle]
490pub unsafe extern "C" fn eip_write_uint(
491 client_id: c_int,
492 tag_name: *const c_char,
493 value: u16,
494) -> c_int {
495 if tag_name.is_null() {
496 return -1;
497 }
498
499 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
500 Ok(s) => s,
501 Err(_) => return -1,
502 };
503
504 let mut clients = FFI_CLIENTS.lock().unwrap();
505 match clients.get_mut(&client_id) {
506 Some(client) => {
507 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Uint(value))) {
508 Ok(_) => 0,
509 Err(_) => -1,
510 }
511 }
512 None => -1,
513 }
514}
515
516#[no_mangle]
518pub unsafe extern "C" fn eip_read_udint(
519 client_id: c_int,
520 tag_name: *const c_char,
521 result: *mut u32,
522) -> c_int {
523 if tag_name.is_null() || result.is_null() {
524 return -1;
525 }
526
527 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
528 Ok(s) => s,
529 Err(_) => return -1,
530 };
531
532 let mut clients = FFI_CLIENTS.lock().unwrap();
533 match clients.get_mut(&client_id) {
534 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
535 Ok(PlcValue::Udint(value)) => {
536 unsafe {
537 *result = value;
538 }
539 0
540 }
541 _ => -1,
542 },
543 None => -1,
544 }
545}
546
547#[no_mangle]
548pub unsafe extern "C" fn eip_write_udint(
549 client_id: c_int,
550 tag_name: *const c_char,
551 value: u32,
552) -> c_int {
553 if tag_name.is_null() {
554 return -1;
555 }
556
557 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
558 Ok(s) => s,
559 Err(_) => return -1,
560 };
561
562 let mut clients = FFI_CLIENTS.lock().unwrap();
563 match clients.get_mut(&client_id) {
564 Some(client) => {
565 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Udint(value))) {
566 Ok(_) => 0,
567 Err(_) => -1,
568 }
569 }
570 None => -1,
571 }
572}
573
574#[no_mangle]
576pub unsafe extern "C" fn eip_read_ulint(
577 client_id: c_int,
578 tag_name: *const c_char,
579 result: *mut u64,
580) -> c_int {
581 if tag_name.is_null() || result.is_null() {
582 return -1;
583 }
584
585 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
586 Ok(s) => s,
587 Err(_) => return -1,
588 };
589
590 let mut clients = FFI_CLIENTS.lock().unwrap();
591 match clients.get_mut(&client_id) {
592 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
593 Ok(PlcValue::Ulint(value)) => {
594 unsafe {
595 *result = value;
596 }
597 0
598 }
599 _ => -1,
600 },
601 None => -1,
602 }
603}
604
605#[no_mangle]
606pub unsafe extern "C" fn eip_write_ulint(
607 client_id: c_int,
608 tag_name: *const c_char,
609 value: u64,
610) -> c_int {
611 if tag_name.is_null() {
612 return -1;
613 }
614
615 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
616 Ok(s) => s,
617 Err(_) => return -1,
618 };
619
620 let mut clients = FFI_CLIENTS.lock().unwrap();
621 match clients.get_mut(&client_id) {
622 Some(client) => {
623 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Ulint(value))) {
624 Ok(_) => 0,
625 Err(_) => -1,
626 }
627 }
628 None => -1,
629 }
630}
631
632#[no_mangle]
634pub unsafe extern "C" fn eip_read_real(
635 client_id: c_int,
636 tag_name: *const c_char,
637 result: *mut f64,
638) -> c_int {
639 if tag_name.is_null() || result.is_null() {
640 return -1;
641 }
642
643 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
644 Ok(s) => s,
645 Err(_) => return -1,
646 };
647
648 let mut clients = FFI_CLIENTS.lock().unwrap();
649 match clients.get_mut(&client_id) {
650 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
651 Ok(PlcValue::Real(value)) => {
652 unsafe {
653 *result = value as f64;
654 }
655 0
656 }
657 _ => -1,
658 },
659 None => -1,
660 }
661}
662
663#[no_mangle]
665pub unsafe extern "C" fn eip_write_real(
666 client_id: c_int,
667 tag_name: *const c_char,
668 value: f64,
669) -> c_int {
670 if tag_name.is_null() {
671 return -1;
672 }
673
674 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
675 Ok(s) => s,
676 Err(_) => return -1,
677 };
678
679 let mut clients = FFI_CLIENTS.lock().unwrap();
680 match clients.get_mut(&client_id) {
681 Some(client) => {
682 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Real(value as f32))) {
683 Ok(_) => 0,
684 Err(_) => -1,
685 }
686 }
687 None => -1,
688 }
689}
690
691#[no_mangle]
693pub unsafe extern "C" fn eip_read_lreal(
694 client_id: c_int,
695 tag_name: *const c_char,
696 result: *mut f64,
697) -> c_int {
698 if tag_name.is_null() || result.is_null() {
699 return -1;
700 }
701
702 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
703 Ok(s) => s,
704 Err(_) => return -1,
705 };
706
707 let mut clients = FFI_CLIENTS.lock().unwrap();
708 match clients.get_mut(&client_id) {
709 Some(client) => match RUNTIME.block_on(client.read_tag(tag_name_str)) {
710 Ok(PlcValue::Lreal(value)) => {
711 unsafe {
712 *result = value;
713 }
714 0
715 }
716 _ => -1,
717 },
718 None => -1,
719 }
720}
721
722#[no_mangle]
723pub unsafe extern "C" fn eip_write_lreal(
724 client_id: c_int,
725 tag_name: *const c_char,
726 value: f64,
727) -> c_int {
728 if tag_name.is_null() {
729 return -1;
730 }
731
732 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
733 Ok(s) => s,
734 Err(_) => return -1,
735 };
736
737 let mut clients = FFI_CLIENTS.lock().unwrap();
738 match clients.get_mut(&client_id) {
739 Some(client) => {
740 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::Lreal(value))) {
741 Ok(_) => 0,
742 Err(_) => -1,
743 }
744 }
745 None => -1,
746 }
747}
748
749#[no_mangle]
760pub unsafe extern "C" fn eip_read_string(
761 client_id: c_int,
762 tag_name: *const c_char,
763 result: *mut c_char,
764 max_length: c_int,
765) -> c_int {
766 if tag_name.is_null() || result.is_null() || max_length <= 0 {
767 return -1;
768 }
769
770 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
771 Ok(s) => s,
772 Err(_) => return -1,
773 };
774
775 let mut clients = FFI_CLIENTS.lock().unwrap();
776 let client = match clients.get_mut(&client_id) {
777 Some(client) => client,
778 None => return -1,
779 };
780
781 let value = match RUNTIME.block_on(client.read_tag(tag_name_str)) {
782 Ok(PlcValue::String(value)) => value,
783 Ok(_) => return -1, Err(_) => return -1, };
786
787 let c_string = match CString::new(value) {
788 Ok(s) => s,
789 Err(_) => return -1,
790 };
791
792 let bytes = c_string.as_bytes_with_nul();
793 if bytes.len() > max_length as usize {
794 return -1; }
796
797 unsafe {
798 ptr::copy_nonoverlapping(bytes.as_ptr(), result as *mut u8, bytes.len());
799 }
800 0
801}
802
803#[no_mangle]
805pub unsafe extern "C" fn eip_write_string(
806 client_id: c_int,
807 tag_name: *const c_char,
808 value: *const c_char,
809) -> c_int {
810 if tag_name.is_null() || value.is_null() {
811 return -1;
812 }
813
814 let tag_name_str = match unsafe { CStr::from_ptr(tag_name) }.to_str() {
815 Ok(s) => s,
816 Err(_) => return -1,
817 };
818
819 let value_str = match unsafe { CStr::from_ptr(value) }.to_str() {
820 Ok(s) => s,
821 Err(_) => return -1,
822 };
823
824 let mut clients = FFI_CLIENTS.lock().unwrap();
825 let client = match clients.get_mut(&client_id) {
826 Some(client) => client,
827 None => return -1,
828 };
829
830 match RUNTIME.block_on(client.write_tag(tag_name_str, PlcValue::String(value_str.to_string())))
831 {
832 Ok(_) => 0,
833 Err(_) => -1,
834 }
835}
836
837#[no_mangle]
839pub unsafe extern "C" fn eip_read_udt(
840 _client_id: c_int,
841 _tag_name: *const c_char,
842 _result: *mut c_char,
843 _max_size: c_int,
844) -> c_int {
845 -1
847}
848
849#[no_mangle]
850pub unsafe extern "C" fn eip_write_udt(
851 _client_id: c_int,
852 _tag_name: *const c_char,
853 _value: *const c_char,
854 _size: c_int,
855) -> c_int {
856 -1
858}
859
860#[no_mangle]
862pub unsafe extern "C" fn eip_discover_tags(_client_id: c_int) -> c_int {
863 0
865}
866
867#[no_mangle]
868pub unsafe extern "C" fn eip_get_tag_metadata(
869 _client_id: c_int,
870 _tag_name: *const c_char,
871 _metadata: *mut u8,
872) -> c_int {
873 -1
875}
876
877#[no_mangle]
879pub unsafe extern "C" fn eip_set_max_packet_size(_client_id: c_int, _size: c_int) -> c_int {
880 0
882}
883
884#[no_mangle]
886pub unsafe extern "C" fn eip_check_health(client_id: c_int, is_healthy: *mut c_int) -> c_int {
887 if is_healthy.is_null() {
888 return -1;
889 }
890
891 let clients = FFI_CLIENTS.lock().unwrap();
892 match clients.get(&client_id) {
893 Some(_) => {
894 unsafe {
895 *is_healthy = 1;
896 }
897 0
898 }
899 None => {
900 unsafe {
901 *is_healthy = 0;
902 }
903 -1
904 }
905 }
906}
907
908#[no_mangle]
909pub unsafe extern "C" fn eip_check_health_detailed(
910 client_id: c_int,
911 is_healthy: *mut c_int,
912) -> c_int {
913 eip_check_health(client_id, is_healthy)
915}
916
917#[no_mangle]
919pub unsafe extern "C" fn eip_read_tags_batch(
920 client_id: c_int,
921 tag_names: *mut *const c_char,
922 tag_count: c_int,
923 results: *mut c_char,
924 results_capacity: c_int,
925) -> c_int {
926 if tag_names.is_null() || results.is_null() || tag_count <= 0 {
927 return -1;
928 }
929
930 let mut clients = FFI_CLIENTS.lock().unwrap();
931 let client = match clients.get_mut(&client_id) {
932 Some(client) => client,
933 None => return -1,
934 };
935
936 let mut tag_name_strs = Vec::new();
938 unsafe {
939 for i in 0..tag_count {
940 let tag_name_ptr = *tag_names.offset(i as isize);
941 if tag_name_ptr.is_null() {
942 return -1;
943 }
944 let tag_name = match CStr::from_ptr(tag_name_ptr).to_str() {
945 Ok(s) => s,
946 Err(_) => return -1,
947 };
948 tag_name_strs.push(tag_name);
949 }
950 }
951
952 let batch_results = RUNTIME.block_on(async { client.read_tags_batch(&tag_name_strs).await });
954
955 let results_data = match batch_results {
956 Ok(results) => {
957 let mut formatted = String::new();
959 for (i, (tag_name, result)) in results.iter().enumerate() {
960 if i > 0 {
961 formatted.push(';');
962 }
963 formatted.push_str(tag_name);
964 formatted.push(':');
965 match result {
966 Ok(value) => formatted.push_str(&format!("{:?}", value)),
967 Err(e) => formatted.push_str(&format!("ERROR:{}", e)),
968 }
969 }
970 formatted
971 }
972 Err(_) => return -1,
973 };
974
975 let results_bytes = results_data.as_bytes();
977 if results_bytes.len() >= results_capacity as usize {
978 return -1;
979 }
980
981 unsafe {
982 std::ptr::copy_nonoverlapping(
983 results_bytes.as_ptr(),
984 results as *mut u8,
985 results_bytes.len(),
986 );
987 *results.add(results_bytes.len()) = 0; }
989
990 0
991}
992
993#[no_mangle]
994pub unsafe extern "C" fn eip_write_tags_batch(
995 client_id: c_int,
996 tag_values: *const c_char,
997 tag_count: c_int,
998 results: *mut c_char,
999 results_capacity: c_int,
1000) -> c_int {
1001 if tag_values.is_null() || results.is_null() || tag_count <= 0 {
1002 return -1;
1003 }
1004
1005 let mut clients = FFI_CLIENTS.lock().unwrap();
1006 let _client = match clients.get_mut(&client_id) {
1007 Some(client) => client,
1008 None => return -1,
1009 };
1010
1011 let _input_str = unsafe {
1013 match CStr::from_ptr(tag_values).to_str() {
1014 Ok(s) => s,
1015 Err(_) => return -1,
1016 }
1017 };
1018
1019 let results_data = "ERROR:Batch write not yet implemented in FFI";
1022 let results_bytes = results_data.as_bytes();
1023
1024 if results_bytes.len() >= results_capacity as usize {
1025 return -1;
1026 }
1027
1028 unsafe {
1029 std::ptr::copy_nonoverlapping(
1030 results_bytes.as_ptr(),
1031 results as *mut u8,
1032 results_bytes.len(),
1033 );
1034 *results.add(results_bytes.len()) = 0; }
1036
1037 0
1038}
1039
1040#[no_mangle]
1041pub unsafe extern "C" fn eip_execute_batch(
1042 client_id: c_int,
1043 operations: *const c_char,
1044 operation_count: c_int,
1045 results: *mut c_char,
1046 results_capacity: c_int,
1047) -> c_int {
1048 if operations.is_null() || results.is_null() || operation_count <= 0 {
1049 return -1;
1050 }
1051
1052 let mut clients = FFI_CLIENTS.lock().unwrap();
1053 let _client = match clients.get_mut(&client_id) {
1054 Some(client) => client,
1055 None => return -1,
1056 };
1057
1058 let _input_str = unsafe {
1060 match CStr::from_ptr(operations).to_str() {
1061 Ok(s) => s,
1062 Err(_) => return -1,
1063 }
1064 };
1065
1066 let results_data = "ERROR:Mixed batch operations not yet implemented in FFI";
1069 let results_bytes = results_data.as_bytes();
1070
1071 if results_bytes.len() >= results_capacity as usize {
1072 return -1;
1073 }
1074
1075 unsafe {
1076 std::ptr::copy_nonoverlapping(
1077 results_bytes.as_ptr(),
1078 results as *mut u8,
1079 results_bytes.len(),
1080 );
1081 *results.add(results_bytes.len()) = 0; }
1083
1084 0
1085}
1086
1087#[no_mangle]
1088pub unsafe extern "C" fn eip_configure_batch_operations(
1089 _client_id: c_int,
1090 _config: *const u8,
1091) -> c_int {
1092 0 }
1094
1095#[no_mangle]
1096pub unsafe extern "C" fn eip_get_batch_config(_client_id: c_int, _config: *mut u8) -> c_int {
1097 -1 }