vips/
init.rs

1//! Global initialization: Ensures initialization only once with 'OnceLock' and automatically shuts down when the process exits.
2//!
3//! # Safety Note
4//!
5//! **Shutdown Timing:**
6//! The libvips library is automatically shut down when the process exits, during static destructor execution (after `main()` completes).
7//! Any operations referencing libvips after `main()` returns (such as in other static destructors or background threads) may result in undefined behavior.
8//! To avoid this, ensure all libvips operations are completed before `main()` exits.
9
10use crate::{take_vips_error, Error, Result};
11use std::ffi::CString;
12use std::sync::OnceLock;
13
14static VIPS: OnceLock<InitGuard> = OnceLock::new();
15
16pub(crate) struct InitGuard;
17
18impl Drop for InitGuard {
19    fn drop(&mut self) {
20        unsafe {
21            // Make sure libvips global resources (cache, thread pool, etc.) are released on exit
22            vips_sys::vips_shutdown();
23        }
24    }
25}
26
27/// Initialize libvips (idempotent). `app_name` can be used for logging and diagnostic display.
28/// If `app_name` is `None`, a default name "vips-rs" will be used.
29///
30/// # Errors
31/// Returns `Error::InitFailed` if initialization fails.
32///
33/// # Example
34/// ```no_run
35/// use vips::*;
36///
37/// fn main() -> Result<()> {
38///     init(Some("my_app"))?;
39///     // Your libvips code here
40///     Ok(())
41/// }
42/// ```
43pub fn init(app_name: Option<&str>) -> Result<()> {
44    // If initialized, return directly.
45    if VIPS.get().is_some() {
46        return Ok(());
47    }
48
49    let cstr = CString::new(app_name.unwrap_or("vips-rs")) // argv0
50        .map_err(|e| Error::InitFailed(format!("invalid app name: {}", e)))?;
51
52    let rc = unsafe { vips_sys::vips_init(cstr.as_ptr()) };
53    if rc != 0 {
54        let msg = take_vips_error().unwrap_or_else(|| "vips_init() failed".to_string());
55        return Err(Error::InitFailed(msg));
56    }
57
58    // Establish a one-time guard, which will automatically drop when the process exits -> vips_shutdown()
59    let _ = VIPS.set(InitGuard);
60    Ok(())
61}
62
63/// Is it currently initialized?
64///
65/// # Safety
66/// This function is safe to call from multiple threads.
67///
68/// # Returns
69/// `true` if libvips has been initialized, `false` otherwise.
70///
71/// /// # Example
72/// ```no_run
73/// use vips::is_initialized;
74///
75///  if is_initialized() {
76///     println!("libvips is initialized");
77///  } else {
78///     println!("libvips is not initialized");
79///  }
80/// ```
81pub fn is_initialized() -> bool {
82    VIPS.get().is_some()
83}