#![allow(clippy::missing_safety_doc)]
use grb_sys2 as ffi;
use std::ffi::{CStr, CString};
use crate::env::Env;
use crate::util::{copy_c_str, AsPtr};
use crate::Result;
#[allow(missing_docs)]
mod param_enums {
include!(concat!(env!("OUT_DIR"), "/param_enums.rs"));
}
#[doc(inline)]
pub use param_enums::enum_exports::*;
pub use param_enums::variant_exports as param;
use crate::constants::GRB_MAX_STRLEN;
use cstr_enum::AsCStr;
pub trait ParamGet<V> {
fn get(&self, env: &Env) -> Result<V>;
}
pub trait ParamSet<V> {
fn set(&self, env: &mut Env, value: V) -> Result<()>;
}
macro_rules! impl_param_get {
($t:ty, $default:expr, $get:path) => {
#[inline]
fn get(&self, env: &Env) -> Result<$t> {
let mut val = $default;
unsafe {
env.check_apicall($get(env.as_mut_ptr(), self.as_cstr().as_ptr(), &mut val))?;
}
Ok(val)
}
};
}
macro_rules! impl_param_set {
($t:ty, $set:path) => {
#[inline]
fn set(&self, env: &mut Env, value: $t) -> Result<()> {
unsafe {
env.check_apicall($set(env.as_mut_ptr(), self.as_cstr().as_ptr(), value))?;
}
Ok(())
}
};
}
impl ParamGet<i32> for IntParam {
impl_param_get! { i32, i32::MIN, ffi::GRBgetintparam }
}
impl ParamSet<i32> for IntParam {
impl_param_set! { i32, ffi::GRBsetintparam }
}
impl ParamGet<f64> for DoubleParam {
impl_param_get! { f64, f64::NAN, ffi::GRBgetdblparam }
}
impl ParamSet<f64> for DoubleParam {
impl_param_set! { f64, ffi::GRBsetdblparam }
}
impl ParamGet<String> for StrParam {
fn get(&self, env: &Env) -> Result<String> {
let mut buf = [0i8; GRB_MAX_STRLEN];
unsafe {
env.check_apicall(ffi::GRBgetstrparam(
env.as_mut_ptr(),
self.as_cstr().as_ptr(),
buf.as_mut_ptr(),
))?;
Ok(copy_c_str(buf.as_ptr()))
}
}
}
impl ParamSet<String> for StrParam {
fn set(&self, env: &mut Env, value: String) -> Result<()> {
let value = CString::new(value)?;
unsafe {
env.check_apicall(ffi::GRBsetstrparam(
env.as_mut_ptr(),
self.as_cstr().as_ptr(),
value.as_ptr(),
))
}
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Undocumented {
name: CString,
}
impl Undocumented {
pub fn new(string: impl Into<Vec<u8>>) -> Result<Undocumented> {
Ok(Undocumented {
name: CString::new(string)?,
})
}
}
impl AsCStr for Undocumented {
fn as_cstr(&self) -> &CStr {
self.name.as_ref()
}
}
impl ParamGet<i32> for &Undocumented {
impl_param_get! { i32, i32::MIN, ffi::GRBgetintparam }
}
impl ParamSet<i32> for &Undocumented {
impl_param_set! { i32, ffi::GRBsetintparam }
}
impl ParamGet<f64> for &Undocumented {
impl_param_get! { f64, f64::NAN, ffi::GRBgetdblparam }
}
impl ParamSet<f64> for &Undocumented {
impl_param_set! { f64, ffi::GRBsetdblparam }
}
impl ParamGet<String> for &Undocumented {
fn get(&self, env: &Env) -> Result<String> {
let mut buf = [0i8; GRB_MAX_STRLEN];
unsafe {
env.check_apicall(ffi::GRBgetstrparam(
env.as_mut_ptr(),
self.as_cstr().as_ptr(),
buf.as_mut_ptr(),
))?;
Ok(copy_c_str(buf.as_ptr()))
}
}
}
impl ParamSet<String> for &Undocumented {
fn set(&self, env: &mut Env, value: String) -> Result<()> {
let value = CString::new(value)?;
unsafe {
env.check_apicall(ffi::GRBsetstrparam(
env.as_mut_ptr(),
self.as_cstr().as_ptr(),
value.as_ptr(),
))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parameter_names() -> crate::Result<()> {
let params : Vec<_> = std::fs::read_to_string(concat!(env!("CARGO_MANIFEST_DIR"), "/build/params.csv")).unwrap()
.lines()
.skip(1)
.map(|line| {
let mut line = line.split(",");
let param = line.next().unwrap();
let ty = line.next().unwrap();
assert_eq!(line.next(), None);
(param.to_string(), ty.to_string())
})
.collect();
let model = crate::Model::new("test")?;
for (param, ty) in params {
let param = Undocumented::new(param).unwrap();
match ty.as_str() {
"dbl" => {
let _v : f64 = model.get_param(¶m)?;
},
"int" => {
let _v : i32 = model.get_param(¶m)?;
},
"str" => {
let _v : String = model.get_param(¶m)?;
},
_ => unreachable!()
}
}
Ok(())
}
}