dl-openvdb-query 0.1.3

Safe Rust wrapper for 3Delight’s OpenVDB metadata query API.
use crate::Api;
extern crate dlopen;
use dlopen::wrapper::{Container, WrapperApi};
use dlopen_derive::WrapperApi;
use std::{
    env,
    os::raw::{c_char, c_float, c_int},
    path::Path,
};

pub type ApiImpl = DynamicApi;

#[derive(WrapperApi)]
struct CApi {
    DlVDBGetFileBBox: extern "C" fn(filename: *const c_char, bbox: *mut f64) -> bool,
    DlVDBGetGridNames: extern "C" fn(
        filename: *const c_char,
        num_grids: *mut c_int,
        grid_names: *mut *const *const c_char,
    ) -> bool,
    DlVDBFreeGridNames: extern "C" fn(grid_names: *const *const c_char) -> bool,

    DlVDBGeneratePoints: extern "C" fn(
        filename: *const c_char,
        densitygrid: *const c_char,
        num_points: *mut usize,
        points: *mut *const c_float,
    ),

    DlVDBFreePoints: extern "C" fn(points: *const c_float),
}

pub struct DynamicApi(Container<CApi>);

#[cfg(target_os = "linux")]
static DELIGHT_APP_PATH: &str = "/usr/local/3delight/lib/lib3delight.so";

#[cfg(target_os = "macos")]
static DELIGHT_APP_PATH: &str = "/Applications/3Delight/lib/lib3delight.dylib";

#[cfg(target_os = "windows")]
static DELIGHT_APP_PATH: &str = "C:/%ProgramFiles%/3Delight/bin/3Delight.dll";

#[cfg(target_os = "linux")]
static DELIGHT_LIB: &str = "lib3delight.so";

#[cfg(target_os = "macos")]
static DELIGHT_LIB: &str = "lib3delight.dylib";

#[cfg(target_os = "windows")]
static DELIGHT_LIB: &str = "3Delight.dll";

impl DynamicApi {
    #[inline]
    pub fn new() -> Result<Self, Box<dyn std::error::Error>> {
        match unsafe { Container::load(DELIGHT_APP_PATH) }
            .or_else(|_| unsafe { Container::load(DELIGHT_LIB) })
            .or_else(|_| match env::var("DELIGHT") {
                Err(e) => Err(Box::new(e) as _),
                Ok(delight) => unsafe {
                    #[cfg(any(target_os = "linux", target_os = "macos"))]
                    let path = Path::new(&delight).join("lib").join(DELIGHT_LIB);
                    #[cfg(target_os = "windows")]
                    let path = Path::new(&delight).join("bin").join(DELIGHT_LIB);

                    Container::load(path)
                }
                .map_err(|e| Box::new(e) as _),
            }) {
            Err(e) => Err(e),
            Ok(api) => Ok(DynamicApi(api)),
        }
    }
}

impl Api for DynamicApi {
    #[inline]
    fn DlVDBGetFileBBox(&self, filename: *const c_char, bbox: *mut f64) -> bool {
        self.0.DlVDBGetFileBBox(filename, bbox)
    }

    #[inline]
    fn DlVDBGetGridNames(
        &self,
        filename: *const c_char,
        num_grids: *mut c_int,
        grid_names: *mut *const *const c_char,
    ) -> bool {
        self.0.DlVDBGetGridNames(filename, num_grids, grid_names)
    }

    #[inline]
    fn DlVDBFreeGridNames(&self, grid_names: *const *const c_char) {
        self.0.DlVDBFreeGridNames(grid_names);
    }

    #[inline]
    fn DlVDBGeneratePoints(
        &self,
        filename: *const c_char,
        densitygrid: *const c_char,
        num_points: *mut usize,
        points: *mut *const c_float,
    ) {
        self.0
            .DlVDBGeneratePoints(filename, densitygrid, num_points, points);
    }

    #[inline]
    fn DlVDBFreePoints(&self, points: *const c_float) {
        self.0.DlVDBFreePoints(points);
    }
}