vips/
instance.rs

1use crate::{Error, Result};
2use std::ffi::CString;
3use std::os::raw::c_int;
4use std::sync::atomic::{AtomicBool, Ordering::Relaxed};
5
6static IS_INSTANTIATED: AtomicBool = AtomicBool::new(false);
7
8/// A singleton instance to manage libvips initialization and shutdown.
9/// # Example
10/// ```no_run
11/// use vips::*;
12///
13/// fn main() -> Result<()> {
14///     let _instance = VipsInstance::new("app_test", true)?;
15///     // Your libvips code here
16///     Ok(())
17/// }
18/// ```
19pub struct VipsInstance {}
20
21impl VipsInstance {
22    /// Create a new VipsInstance, initializing libvips.
23    /// This can only be done once per program execution.
24    /// Subsequent attempts will return an error.
25    /// # Arguments
26    /// * `name` - Application name for libvips initialization.
27    /// * `leak_test` - If true, enables leak testing in libvips.
28    ///
29    /// # Errors
30    /// Returns an error if an instance already exists.
31    ///
32    /// # Example
33    /// ```no_run
34    /// use vips::*;
35    ///
36    /// fn main() -> Result<()> {
37    ///     let _instance = VipsInstance::new("app_test", true)?;
38    ///     // Your libvips code here
39    ///     Ok(())
40    /// }
41    /// ```
42    /// # Safety Note
43    ///
44    /// **Shutdown Timing:**
45    /// The libvips library is automatically shut down when the `VipsInstance` is dropped (typically
46    /// at the end of `main()`). Any operations referencing libvips after this point
47    /// (such as in other static destructors or background threads) may result in undefined behavior.
48    /// To avoid this, ensure all libvips operations are completed before the `Vips
49    /// Instance` is dropped.
50    ///
51    pub fn new(name: &str, leak_test: bool) -> Result<VipsInstance> {
52        // Try to set false -> true, allowing only once
53        match IS_INSTANTIATED.compare_exchange(false, true, Relaxed, Relaxed) {
54            Ok(_) => {
55                let c = CString::new(name)
56                    .map_err(|e| Error::InitFailed(format!("invalid name: {}", e)))?;
57                unsafe {
58                    vips_sys::vips_init(c.as_ptr());
59                    if leak_test {
60                        vips_sys::vips_leak_set(leak_test as c_int);
61                    }
62                }
63                Ok(VipsInstance {})
64            }
65            Err(_) => Err(Error::Other(
66                "You cannot create VipsInstance more than once.".to_string(),
67            )),
68        }
69    }
70}
71
72impl Drop for VipsInstance {
73    fn drop(&mut self) {
74        unsafe {
75            vips_sys::vips_shutdown();
76        }
77        // Note: libvips does not support re-initialization after shutdown, so IS_INSTANTIATED is not reset here.
78    }
79}