use std::{
ffi::{c_char, CStr, CString},
ptr::{null, null_mut},
rc::Rc,
};
use crate::{error::check_err, ffi};
#[derive(Clone)]
pub struct GRBEnv {
inner: Rc<*mut ffi::GRBenv>,
}
impl GRBEnv {
pub fn inner(&self) -> *mut ffi::GRBenv {
*self.inner
}
pub fn new(empty: bool, logfilename: Option<&str>) -> Result<GRBEnv, String> {
let mut env_ptr = null_mut();
let logfilename_cstring = logfilename
.map(|s| CString::new(s))
.transpose()
.map_err(|_| "Failed to convert logfilename to CString".to_string())?;
let logfilename_ptr = logfilename_cstring
.as_ref()
.map(|cstr| cstr.as_ptr())
.unwrap_or(null());
let error = if empty {
unsafe { ffi::GRBemptyenv(&mut env_ptr) }
} else {
unsafe { ffi::GRBloadenv(&mut env_ptr, logfilename_ptr) }
};
let env = GRBEnv {
inner: Rc::new(env_ptr),
};
env.get_error(error).unwrap();
Ok(env)
}
pub fn start(&mut self) {
unsafe {
ffi::GRBstartenv(*self.inner);
}
}
pub fn get_error(&self, error_code: i32) -> Result<(), String> {
match check_err(error_code) {
Err(e) => unsafe {
Err(format!(
"ERROR CODE {}: {}",
e,
CStr::from_ptr(ffi::GRBgeterrormsg(self.inner()) as *mut c_char)
.to_string_lossy()
))
},
Ok(_o) => Ok(()),
}
}
}
impl Default for GRBEnv {
fn default() -> Self {
GRBEnv::new(false, None).expect("Failed to create default GRBenv")
}
}
impl Drop for GRBEnv {
fn drop(&mut self) {
if Rc::strong_count(&self.inner) > 1 {
return;
}
unsafe {
ffi::GRBfreeenv(*self.inner);
}
}
}