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}