1#![allow(non_snake_case)]
8
9use std::os::raw::{c_char, c_double, c_int, c_long};
10use std::path::Path;
11
12use libloading::Library;
13
14pub const REFPROP_STRLEN: usize = 255;
16pub const REFPROP_FILESTR: usize = 10000;
17pub const REFPROP_NC_MAX: usize = 20;
18
19#[derive(Debug)]
21pub enum RefpropSysError {
22 LibraryLoadFailed(String),
24 SymbolNotFound(String),
26}
27
28impl std::fmt::Display for RefpropSysError {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 match self {
31 Self::LibraryLoadFailed(msg) => write!(f, "REFPROP library load failed: {msg}"),
32 Self::SymbolNotFound(sym) => {
33 write!(f, "Symbol not found in REFPROP library: {sym}")
34 }
35 }
36 }
37}
38
39impl std::error::Error for RefpropSysError {}
40
41type FnSetpath = unsafe extern "C" fn(*const c_char, c_long);
47
48type FnSetup = unsafe extern "C" fn(
50 *const c_int,
51 *const c_char,
52 *const c_char,
53 *const c_char,
54 *mut c_int,
55 *mut c_char,
56 c_long,
57 c_long,
58 c_long,
59 c_long,
60);
61
62type FnFlash = unsafe extern "C" fn(
65 *const c_double,
66 *const c_double,
67 *const c_double,
68 *mut c_double,
69 *mut c_double,
70 *mut c_double,
71 *mut c_double,
72 *mut c_double,
73 *mut c_double,
74 *mut c_double,
75 *mut c_double,
76 *mut c_double,
77 *mut c_double,
78 *mut c_double,
79 *mut c_double,
80 *mut c_int,
81 *mut c_char,
82 c_long,
83);
84
85type FnFlashKr = unsafe extern "C" fn(
89 *const c_double,
90 *const c_double,
91 *const c_double,
92 *mut c_double,
93 *mut c_double,
94 *mut c_double,
95 *mut c_double,
96 *mut c_double,
97 *mut c_double,
98 *mut c_double,
99 *mut c_double,
100 *mut c_double,
101 *mut c_double,
102 *mut c_double,
103 *mut c_double,
104 *mut c_double,
105 *mut c_int,
106 *mut c_char,
107 c_long,
108);
109
110type FnSat = unsafe extern "C" fn(
113 *const c_double,
114 *const c_double,
115 *const c_int,
116 *mut c_double,
117 *mut c_double,
118 *mut c_double,
119 *mut c_double,
120 *mut c_double,
121 *mut c_int,
122 *mut c_char,
123 c_long,
124);
125
126type FnCritp = unsafe extern "C" fn(
128 *const c_double,
129 *mut c_double,
130 *mut c_double,
131 *mut c_double,
132 *mut c_int,
133 *mut c_char,
134 c_long,
135);
136
137type FnTrnprp = unsafe extern "C" fn(
139 *const c_double,
140 *const c_double,
141 *const c_double,
142 *mut c_double,
143 *mut c_double,
144 *mut c_int,
145 *mut c_char,
146 c_long,
147);
148
149type FnSetmix = unsafe extern "C" fn(
151 *const c_char,
152 *const c_char,
153 *const c_char,
154 *mut c_int,
155 *mut c_char,
156 *mut c_double,
157 *mut c_int,
158 *mut c_char,
159 c_long,
160 c_long,
161 c_long,
162 c_long,
163 c_long,
164);
165
166type FnTherm = unsafe extern "C" fn(
168 *const c_double,
169 *const c_double,
170 *const c_double,
171 *mut c_double,
172 *mut c_double,
173 *mut c_double,
174 *mut c_double,
175 *mut c_double,
176 *mut c_double,
177 *mut c_double,
178 *mut c_double,
179);
180
181type FnInfo = unsafe extern "C" fn(
183 *const c_int,
184 *mut c_double,
185 *mut c_double,
186 *mut c_double,
187 *mut c_double,
188 *mut c_double,
189 *mut c_double,
190 *mut c_double,
191 *mut c_double,
192 *mut c_double,
193 *mut c_double,
194);
195
196pub struct RefpropLibrary {
208 _lib: Library,
211
212 fn_setpath: FnSetpath,
214 fn_setup: FnSetup,
215 fn_tpflsh: FnFlash,
216 fn_phflsh: FnFlash,
217 fn_psflsh: FnFlash,
218 fn_satt: FnSat,
219 fn_satp: FnSat,
220 fn_critp: FnCritp,
221 fn_trnprp: FnTrnprp,
222 fn_setmix: FnSetmix,
223 fn_tdflsh: FnFlash,
224 fn_pdflsh: FnFlash,
225 fn_thflsh: FnFlashKr,
226 fn_tsflsh: FnFlashKr,
227 fn_dhflsh: FnFlash,
228 fn_dsflsh: FnFlash,
229 fn_hsflsh: FnFlash,
230 fn_therm: FnTherm,
231 fn_info: FnInfo,
232}
233
234impl RefpropLibrary {
235 fn resolve<T: Copy>(lib: &Library, name: &[u8]) -> Result<T, RefpropSysError> {
240 let sym: libloading::Symbol<T> = unsafe { lib.get(name) }.map_err(|_| {
244 let display =
246 String::from_utf8_lossy(&name[..name.len().saturating_sub(1)]).to_string();
247 RefpropSysError::SymbolNotFound(display)
248 })?;
249 Ok(*sym)
250 }
251
252 fn resolve_all(lib: Library) -> Result<Self, RefpropSysError> {
255 Ok(Self {
256 fn_setpath: Self::resolve(&lib, b"SETPATHdll\0")?,
257 fn_setup: Self::resolve(&lib, b"SETUPdll\0")?,
258 fn_tpflsh: Self::resolve(&lib, b"TPFLSHdll\0")?,
259 fn_phflsh: Self::resolve(&lib, b"PHFLSHdll\0")?,
260 fn_psflsh: Self::resolve(&lib, b"PSFLSHdll\0")?,
261 fn_satt: Self::resolve(&lib, b"SATTdll\0")?,
262 fn_satp: Self::resolve(&lib, b"SATPdll\0")?,
263 fn_critp: Self::resolve(&lib, b"CRITPdll\0")?,
264 fn_trnprp: Self::resolve(&lib, b"TRNPRPdll\0")?,
265 fn_setmix: Self::resolve(&lib, b"SETMIXdll\0")?,
266 fn_tdflsh: Self::resolve(&lib, b"TDFLSHdll\0")?,
267 fn_pdflsh: Self::resolve(&lib, b"PDFLSHdll\0")?,
268 fn_thflsh: Self::resolve(&lib, b"THFLSHdll\0")?,
269 fn_tsflsh: Self::resolve(&lib, b"TSFLSHdll\0")?,
270 fn_dhflsh: Self::resolve(&lib, b"DHFLSHdll\0")?,
271 fn_dsflsh: Self::resolve(&lib, b"DSFLSHdll\0")?,
272 fn_hsflsh: Self::resolve(&lib, b"HSFLSHdll\0")?,
273 fn_therm: Self::resolve(&lib, b"THERMdll\0")?,
274 fn_info: Self::resolve(&lib, b"INFOdll\0")?,
275 _lib: lib,
276 })
277 }
278
279 pub fn load_from_dir(dir: &Path) -> Result<Self, RefpropSysError> {
291 let candidates: &[&str] = if cfg!(target_os = "windows") {
293 if cfg!(target_pointer_width = "64") {
294 &["REFPRP64.DLL", "REFPROP.DLL", "refprop.dll"]
295 } else {
296 &["REFPROP.DLL", "refprop.dll", "REFPRP64.DLL"]
297 }
298 } else if cfg!(target_os = "macos") {
299 &["librefprop.dylib", "libREFPROP.dylib"]
300 } else {
301 &["librefprop.so", "libREFPROP.so"]
302 };
303
304 let mut errors = Vec::new();
305
306 for name in candidates {
309 let full = dir.join(name);
310 if full.exists() {
311 match unsafe { Library::new(&full) } {
312 Ok(lib) => return Self::resolve_all(lib),
313 Err(e) => {
314 errors.push(format!("{}: {e}", full.display()));
315 }
316 }
317 }
318 }
319
320 for name in candidates {
322 if let Ok(lib) = unsafe { Library::new(*name) } {
323 return Self::resolve_all(lib);
324 }
325 }
326
327 let detail = if errors.is_empty() {
328 format!(
329 "No REFPROP library found in {} (tried: {candidates:?})",
330 dir.display()
331 )
332 } else {
333 format!(
334 "REFPROP library found but could not be loaded:\n - {}",
335 errors.join("\n - ")
336 )
337 };
338 Err(RefpropSysError::LibraryLoadFailed(detail))
339 }
340
341 pub fn load_from_file(path: &Path) -> Result<Self, RefpropSysError> {
343 let lib = unsafe { Library::new(path) }
344 .map_err(|e| RefpropSysError::LibraryLoadFailed(format!("{}: {e}", path.display())))?;
345 Self::resolve_all(lib)
346 }
347
348 pub unsafe fn SETPATHdll(&self, hpath: *const c_char, length: c_long) {
357 unsafe { (self.fn_setpath)(hpath, length) };
358 }
359
360 pub unsafe fn SETUPdll(
362 &self,
363 nc: *const c_int,
364 hfld: *const c_char,
365 hfmix: *const c_char,
366 hrf: *const c_char,
367 ierr: *mut c_int,
368 herr: *mut c_char,
369 hfld_length: c_long,
370 hfmix_length: c_long,
371 hrf_length: c_long,
372 herr_length: c_long,
373 ) {
374 unsafe {
375 (self.fn_setup)(
376 nc,
377 hfld,
378 hfmix,
379 hrf,
380 ierr,
381 herr,
382 hfld_length,
383 hfmix_length,
384 hrf_length,
385 herr_length,
386 );
387 }
388 }
389
390 pub unsafe fn TPFLSHdll(
392 &self,
393 t: *const c_double,
394 p: *const c_double,
395 z: *const c_double,
396 d: *mut c_double,
397 dl: *mut c_double,
398 dv: *mut c_double,
399 x: *mut c_double,
400 y: *mut c_double,
401 q: *mut c_double,
402 e: *mut c_double,
403 h: *mut c_double,
404 s: *mut c_double,
405 cv: *mut c_double,
406 cp: *mut c_double,
407 w: *mut c_double,
408 ierr: *mut c_int,
409 herr: *mut c_char,
410 herr_length: c_long,
411 ) {
412 unsafe {
413 (self.fn_tpflsh)(
414 t,
415 p,
416 z,
417 d,
418 dl,
419 dv,
420 x,
421 y,
422 q,
423 e,
424 h,
425 s,
426 cv,
427 cp,
428 w,
429 ierr,
430 herr,
431 herr_length,
432 );
433 }
434 }
435
436 pub unsafe fn PHFLSHdll(
438 &self,
439 p: *const c_double,
440 h: *const c_double,
441 z: *const c_double,
442 t: *mut c_double,
443 d: *mut c_double,
444 dl: *mut c_double,
445 dv: *mut c_double,
446 x: *mut c_double,
447 y: *mut c_double,
448 q: *mut c_double,
449 e: *mut c_double,
450 s: *mut c_double,
451 cv: *mut c_double,
452 cp: *mut c_double,
453 w: *mut c_double,
454 ierr: *mut c_int,
455 herr: *mut c_char,
456 herr_length: c_long,
457 ) {
458 unsafe {
459 (self.fn_phflsh)(
460 p,
461 h,
462 z,
463 t,
464 d,
465 dl,
466 dv,
467 x,
468 y,
469 q,
470 e,
471 s,
472 cv,
473 cp,
474 w,
475 ierr,
476 herr,
477 herr_length,
478 );
479 }
480 }
481
482 pub unsafe fn PSFLSHdll(
484 &self,
485 p: *const c_double,
486 s: *const c_double,
487 z: *const c_double,
488 t: *mut c_double,
489 d: *mut c_double,
490 dl: *mut c_double,
491 dv: *mut c_double,
492 x: *mut c_double,
493 y: *mut c_double,
494 q: *mut c_double,
495 e: *mut c_double,
496 h: *mut c_double,
497 cv: *mut c_double,
498 cp: *mut c_double,
499 w: *mut c_double,
500 ierr: *mut c_int,
501 herr: *mut c_char,
502 herr_length: c_long,
503 ) {
504 unsafe {
505 (self.fn_psflsh)(
506 p,
507 s,
508 z,
509 t,
510 d,
511 dl,
512 dv,
513 x,
514 y,
515 q,
516 e,
517 h,
518 cv,
519 cp,
520 w,
521 ierr,
522 herr,
523 herr_length,
524 );
525 }
526 }
527
528 pub unsafe fn SATTdll(
530 &self,
531 t: *const c_double,
532 z: *const c_double,
533 kph: *const c_int,
534 p: *mut c_double,
535 dl: *mut c_double,
536 dv: *mut c_double,
537 x: *mut c_double,
538 y: *mut c_double,
539 ierr: *mut c_int,
540 herr: *mut c_char,
541 herr_length: c_long,
542 ) {
543 unsafe { (self.fn_satt)(t, z, kph, p, dl, dv, x, y, ierr, herr, herr_length) };
544 }
545
546 pub unsafe fn SATPdll(
548 &self,
549 p: *const c_double,
550 z: *const c_double,
551 kph: *const c_int,
552 t: *mut c_double,
553 dl: *mut c_double,
554 dv: *mut c_double,
555 x: *mut c_double,
556 y: *mut c_double,
557 ierr: *mut c_int,
558 herr: *mut c_char,
559 herr_length: c_long,
560 ) {
561 unsafe { (self.fn_satp)(p, z, kph, t, dl, dv, x, y, ierr, herr, herr_length) };
562 }
563
564 pub unsafe fn CRITPdll(
566 &self,
567 z: *const c_double,
568 tcrit: *mut c_double,
569 pcrit: *mut c_double,
570 dcrit: *mut c_double,
571 ierr: *mut c_int,
572 herr: *mut c_char,
573 herr_length: c_long,
574 ) {
575 unsafe { (self.fn_critp)(z, tcrit, pcrit, dcrit, ierr, herr, herr_length) };
576 }
577
578 pub unsafe fn TRNPRPdll(
580 &self,
581 t: *const c_double,
582 d: *const c_double,
583 z: *const c_double,
584 eta: *mut c_double,
585 tcx: *mut c_double,
586 ierr: *mut c_int,
587 herr: *mut c_char,
588 herr_length: c_long,
589 ) {
590 unsafe { (self.fn_trnprp)(t, d, z, eta, tcx, ierr, herr, herr_length) };
591 }
592
593 pub unsafe fn SETMIXdll(
598 &self,
599 hmxnme: *const c_char,
600 hfmix: *const c_char,
601 hrf: *const c_char,
602 nc: *mut c_int,
603 hfld: *mut c_char,
604 z: *mut c_double,
605 ierr: *mut c_int,
606 herr: *mut c_char,
607 hmxnme_length: c_long,
608 hfmix_length: c_long,
609 hrf_length: c_long,
610 hfld_length: c_long,
611 herr_length: c_long,
612 ) {
613 unsafe {
614 (self.fn_setmix)(
615 hmxnme,
616 hfmix,
617 hrf,
618 nc,
619 hfld,
620 z,
621 ierr,
622 herr,
623 hmxnme_length,
624 hfmix_length,
625 hrf_length,
626 hfld_length,
627 herr_length,
628 );
629 }
630 }
631
632 pub unsafe fn TDFLSHdll(
634 &self,
635 t: *const c_double,
636 d: *const c_double,
637 z: *const c_double,
638 p: *mut c_double,
639 dl: *mut c_double,
640 dv: *mut c_double,
641 x: *mut c_double,
642 y: *mut c_double,
643 q: *mut c_double,
644 e: *mut c_double,
645 h: *mut c_double,
646 s: *mut c_double,
647 cv: *mut c_double,
648 cp: *mut c_double,
649 w: *mut c_double,
650 ierr: *mut c_int,
651 herr: *mut c_char,
652 herr_length: c_long,
653 ) {
654 unsafe {
655 (self.fn_tdflsh)(
656 t,
657 d,
658 z,
659 p,
660 dl,
661 dv,
662 x,
663 y,
664 q,
665 e,
666 h,
667 s,
668 cv,
669 cp,
670 w,
671 ierr,
672 herr,
673 herr_length,
674 );
675 }
676 }
677
678 pub unsafe fn PDFLSHdll(
680 &self,
681 p: *const c_double,
682 d: *const c_double,
683 z: *const c_double,
684 t: *mut c_double,
685 dl: *mut c_double,
686 dv: *mut c_double,
687 x: *mut c_double,
688 y: *mut c_double,
689 q: *mut c_double,
690 e: *mut c_double,
691 h: *mut c_double,
692 s: *mut c_double,
693 cv: *mut c_double,
694 cp: *mut c_double,
695 w: *mut c_double,
696 ierr: *mut c_int,
697 herr: *mut c_char,
698 herr_length: c_long,
699 ) {
700 unsafe {
701 (self.fn_pdflsh)(
702 p,
703 d,
704 z,
705 t,
706 dl,
707 dv,
708 x,
709 y,
710 q,
711 e,
712 h,
713 s,
714 cv,
715 cp,
716 w,
717 ierr,
718 herr,
719 herr_length,
720 );
721 }
722 }
723
724 pub unsafe fn THFLSHdll(
726 &self,
727 t: *const c_double,
728 h: *const c_double,
729 z: *const c_double,
730 kr: *mut c_double,
731 p: *mut c_double,
732 d: *mut c_double,
733 dl: *mut c_double,
734 dv: *mut c_double,
735 x: *mut c_double,
736 y: *mut c_double,
737 q: *mut c_double,
738 e: *mut c_double,
739 s: *mut c_double,
740 cv: *mut c_double,
741 cp: *mut c_double,
742 w: *mut c_double,
743 ierr: *mut c_int,
744 herr: *mut c_char,
745 herr_length: c_long,
746 ) {
747 unsafe {
748 (self.fn_thflsh)(
749 t,
750 h,
751 z,
752 kr,
753 p,
754 d,
755 dl,
756 dv,
757 x,
758 y,
759 q,
760 e,
761 s,
762 cv,
763 cp,
764 w,
765 ierr,
766 herr,
767 herr_length,
768 );
769 }
770 }
771
772 pub unsafe fn TSFLSHdll(
774 &self,
775 t: *const c_double,
776 s: *const c_double,
777 z: *const c_double,
778 kr: *mut c_double,
779 p: *mut c_double,
780 d: *mut c_double,
781 dl: *mut c_double,
782 dv: *mut c_double,
783 x: *mut c_double,
784 y: *mut c_double,
785 q: *mut c_double,
786 e: *mut c_double,
787 h: *mut c_double,
788 cv: *mut c_double,
789 cp: *mut c_double,
790 w: *mut c_double,
791 ierr: *mut c_int,
792 herr: *mut c_char,
793 herr_length: c_long,
794 ) {
795 unsafe {
796 (self.fn_tsflsh)(
797 t,
798 s,
799 z,
800 kr,
801 p,
802 d,
803 dl,
804 dv,
805 x,
806 y,
807 q,
808 e,
809 h,
810 cv,
811 cp,
812 w,
813 ierr,
814 herr,
815 herr_length,
816 );
817 }
818 }
819
820 pub unsafe fn DHFLSHdll(
822 &self,
823 d: *const c_double,
824 h: *const c_double,
825 z: *const c_double,
826 t: *mut c_double,
827 p: *mut c_double,
828 dl: *mut c_double,
829 dv: *mut c_double,
830 x: *mut c_double,
831 y: *mut c_double,
832 q: *mut c_double,
833 e: *mut c_double,
834 s: *mut c_double,
835 cv: *mut c_double,
836 cp: *mut c_double,
837 w: *mut c_double,
838 ierr: *mut c_int,
839 herr: *mut c_char,
840 herr_length: c_long,
841 ) {
842 unsafe {
843 (self.fn_dhflsh)(
844 d,
845 h,
846 z,
847 t,
848 p,
849 dl,
850 dv,
851 x,
852 y,
853 q,
854 e,
855 s,
856 cv,
857 cp,
858 w,
859 ierr,
860 herr,
861 herr_length,
862 );
863 }
864 }
865
866 pub unsafe fn DSFLSHdll(
868 &self,
869 d: *const c_double,
870 s: *const c_double,
871 z: *const c_double,
872 t: *mut c_double,
873 p: *mut c_double,
874 dl: *mut c_double,
875 dv: *mut c_double,
876 x: *mut c_double,
877 y: *mut c_double,
878 q: *mut c_double,
879 e: *mut c_double,
880 h: *mut c_double,
881 cv: *mut c_double,
882 cp: *mut c_double,
883 w: *mut c_double,
884 ierr: *mut c_int,
885 herr: *mut c_char,
886 herr_length: c_long,
887 ) {
888 unsafe {
889 (self.fn_dsflsh)(
890 d,
891 s,
892 z,
893 t,
894 p,
895 dl,
896 dv,
897 x,
898 y,
899 q,
900 e,
901 h,
902 cv,
903 cp,
904 w,
905 ierr,
906 herr,
907 herr_length,
908 );
909 }
910 }
911
912 pub unsafe fn HSFLSHdll(
914 &self,
915 h: *const c_double,
916 s: *const c_double,
917 z: *const c_double,
918 t: *mut c_double,
919 p: *mut c_double,
920 d: *mut c_double,
921 dl: *mut c_double,
922 dv: *mut c_double,
923 x: *mut c_double,
924 y: *mut c_double,
925 q: *mut c_double,
926 e: *mut c_double,
927 cv: *mut c_double,
928 cp: *mut c_double,
929 w: *mut c_double,
930 ierr: *mut c_int,
931 herr: *mut c_char,
932 herr_length: c_long,
933 ) {
934 unsafe {
935 (self.fn_hsflsh)(
936 h,
937 s,
938 z,
939 t,
940 p,
941 d,
942 dl,
943 dv,
944 x,
945 y,
946 q,
947 e,
948 cv,
949 cp,
950 w,
951 ierr,
952 herr,
953 herr_length,
954 );
955 }
956 }
957
958 pub unsafe fn THERMdll(
962 &self,
963 t: *const c_double,
964 d: *const c_double,
965 z: *const c_double,
966 p: *mut c_double,
967 e: *mut c_double,
968 h: *mut c_double,
969 s: *mut c_double,
970 cv: *mut c_double,
971 cp: *mut c_double,
972 w: *mut c_double,
973 hjt: *mut c_double,
974 ) {
975 unsafe { (self.fn_therm)(t, d, z, p, e, h, s, cv, cp, w, hjt) };
976 }
977
978 pub unsafe fn INFOdll(
980 &self,
981 icomp: *const c_int,
982 wmm: *mut c_double,
983 ttrp: *mut c_double,
984 tnbpt: *mut c_double,
985 tc: *mut c_double,
986 pc: *mut c_double,
987 dc: *mut c_double,
988 zc: *mut c_double,
989 acf: *mut c_double,
990 dip: *mut c_double,
991 rgas: *mut c_double,
992 ) {
993 unsafe { (self.fn_info)(icomp, wmm, ttrp, tnbpt, tc, pc, dc, zc, acf, dip, rgas) };
994 }
995}
996
997pub fn find_dll_in_dir(dir: &Path) -> Option<std::path::PathBuf> {
1010 let candidates: &[&str] = if cfg!(target_os = "windows") {
1011 if cfg!(target_pointer_width = "64") {
1012 &["REFPRP64.DLL", "REFPROP.DLL", "refprop.dll"]
1013 } else {
1014 &["REFPROP.DLL", "refprop.dll", "REFPRP64.DLL"]
1015 }
1016 } else if cfg!(target_os = "macos") {
1017 &["librefprop.dylib", "libREFPROP.dylib"]
1018 } else {
1019 &["librefprop.so", "libREFPROP.so"]
1020 };
1021
1022 for name in candidates {
1023 let full = dir.join(name);
1024 if full.exists() {
1025 return Some(full);
1026 }
1027 }
1028 None
1029}
1030
1031pub fn to_c_string(s: &str, max_len: usize) -> Vec<c_char> {
1036 let mut buffer = vec![0 as c_char; max_len];
1037 let bytes = s.as_bytes();
1038 let copy_len = bytes.len().min(max_len - 1);
1039 for i in 0..copy_len {
1040 buffer[i] = bytes[i] as c_char;
1041 }
1042 buffer
1043}
1044
1045pub fn from_c_string(buffer: &[c_char]) -> String {
1048 let bytes: Vec<u8> = buffer
1049 .iter()
1050 .take_while(|&&c| c != 0)
1051 .map(|&c| c as u8)
1052 .collect();
1053 String::from_utf8_lossy(&bytes).trim().to_string()
1054}