Search code examples
cachingstaticrustffi

Caching externally-loaded data in a static variable


I'd like to load data from a file, then cache this data (including quite large arrays) in a static variable. This obviously is not the preferred way of doing this, but:

  1. I'm writing a Rust library invoked by a C(++) program, and don't currently have any objects which out-live invocation of the Rust functions. Using a static avoids me having to hack up the C code.
  2. The program doesn't do anything concurrently internally, so synchronisation is not an issue.

How can this be done in Rust?

I have found lazy-static which solves a similar problem, but only for code not requiring external resources (i.e. items which could in theory be evaluated at compile time).


Solution

  • You cannot do the initialization at program start, but you can do it at the first method call. All further calls will access the cached value instead of recomputing your value.

    Since rust forbids things with destructors inside static variables, you need to do your own cleanup management. Logically this means you need unsafe code to break rust's safety system. The following example uses a static mut variable to cache a heap allocated object (an i32 in this case). The cacheload function works like a Singleton.

    Just remember to call cachefree() from c after you are done.

    use std::{ptr, mem};
    
    static mut cache: *const i32 = 0 as *const i32;
    
    unsafe fn cacheload() -> i32 {
        if cache == ptr::null() {
            // do an expensive operation here
            cache = mem::transmute(Box::new(42));
        }
        return *cache;
    }
    
    unsafe fn cachefree() {
        if cache != ptr::null() {
            let temp: Box<i32> = mem::transmute(cache);
            cache = ptr::null();
            drop(temp);
        }
    }
    
    fn main() {
        let x;
        unsafe {
            x = cacheload();
            cachefree();
        }
        println!("{}" , x);
    }