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}