1#![allow(non_upper_case_globals, non_camel_case_types, non_snake_case)]
16#![allow(clippy::missing_safety_doc)]
17
18#[cfg(not(feature = "bindgen"))]
21#[allow(clippy::all)]
22mod ffi {
23 include!("bindings/prebuilt.rs");
24}
25
26#[cfg(feature = "bindgen")]
28#[allow(clippy::all)]
29mod ffi {
30 include!(concat!(env!("OUT_DIR"), "/binding.rs"));
31}
32
33pub use ffi::*;
34
35const _: () = {
37 assert!(core::mem::size_of::<gsize>() == core::mem::size_of::<usize>());
38 assert!(core::mem::size_of::<gssize>() == core::mem::size_of::<isize>());
39 assert!(core::mem::size_of::<GType>() == core::mem::size_of::<usize>());
40};
41
42#[cfg(feature = "helpers")]
44pub mod helpers {
45 use super::*;
46 use std::ffi::CString;
47 use std::sync::{Mutex, OnceLock};
48
49 static INIT: OnceLock<()> = OnceLock::new();
50 static INIT_LOCK: Mutex<()> = Mutex::new(());
51
52 pub fn is_initialized() -> bool {
54 INIT.get().is_some()
55 }
56
57 pub fn init(argv0: &str) -> Result<(), i32> {
59 if INIT.get().is_some() {
61 return Ok(());
62 }
63 let _guard = INIT_LOCK.lock().unwrap_or_else(|e| e.into_inner());
64 if INIT.get().is_some() {
65 return Ok(());
66 }
67 let c = CString::new(argv0).map_err(|_| -1)?;
68 let rc = unsafe { vips_init(c.as_ptr()) };
69 if rc != 0 {
70 return Err(rc);
71 }
72 let _ = INIT.set(());
73 Ok(())
74 }
75
76 pub unsafe fn shutdown() {
83 unsafe { vips_shutdown() }
85 }
86
87 pub fn version() -> (i32, i32, i32) {
89 static VER: OnceLock<(i32, i32, i32)> = OnceLock::new();
90 *VER.get_or_init(|| unsafe { (vips_version(0), vips_version(1), vips_version(2)) })
91 }
92
93 pub fn version_string() -> &'static str {
98 static STR: OnceLock<&'static str> = OnceLock::new();
99 STR.get_or_init(|| unsafe {
101 let p = vips_version_string();
102 if p.is_null() {
103 ""
104 } else {
105 std::ffi::CStr::from_ptr(p).to_str().unwrap_or("")
106 }
107 })
108 }
109}
110
111#[cfg(all(test, feature = "helpers"))]
112mod tests {
113 use super::helpers;
114
115 #[test]
116 fn init_and_version() {
117 assert_eq!(helpers::init("invalid\0name"), Err(-1));
118 helpers::init("vips-sys-test").expect("vips_init");
119 let (maj, min, mic) = helpers::version();
120 assert!(maj >= 0 && min >= 0 && mic >= 0);
121 assert!(!helpers::version_string().is_empty());
122 assert_eq!(helpers::version(), (maj, min, mic));
124 std::thread::scope(|scope| {
125 for _ in 0..8 {
126 scope.spawn(|| helpers::init("parallel-init").unwrap());
127 }
128 });
129 }
130}