use std::{
ffi::{CString, NulError},
os::raw::{c_char, c_long},
sync::Mutex,
};
use super::ffi::{self, InputPair, OutputParam};
const MSG_BUF_LEN: usize = 512;
static COOLPROP_LOCK: Mutex<()> = Mutex::new(());
pub struct AbstractState {
handle: c_long,
}
#[derive(Debug, thiserror::Error)]
#[non_exhaustive]
pub enum WrapperError {
#[error("invalid C string argument: {0}")]
InvalidCString(#[from] NulError),
#[error("{0}")]
CoolProp(String),
}
impl AbstractState {
pub fn new(backend: &str, fluid: &str) -> Result<Self, WrapperError> {
let backend_c = CString::new(backend)?;
let fluid_c = CString::new(fluid)?;
let mut errcode: c_long = 0;
let mut buf = [0u8; MSG_BUF_LEN];
let _guard = COOLPROP_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let handle = unsafe {
ffi::AbstractState_factory(
backend_c.as_ptr(),
fluid_c.as_ptr(),
&raw mut errcode,
buf.as_mut_ptr().cast::<c_char>(),
c_long::try_from(MSG_BUF_LEN).expect("buffer length fits c_long"),
)
};
if errcode != 0 {
return Err(WrapperError::CoolProp(read_message(&buf)));
}
Ok(Self { handle })
}
pub fn update(&mut self, pair: InputPair, v1: f64, v2: f64) -> Result<(), WrapperError> {
let mut errcode: c_long = 0;
let mut buf = [0u8; MSG_BUF_LEN];
let _guard = COOLPROP_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
unsafe {
ffi::AbstractState_update(
self.handle,
pair.as_c_long(),
v1,
v2,
&raw mut errcode,
buf.as_mut_ptr().cast::<c_char>(),
c_long::try_from(MSG_BUF_LEN).expect("buffer length fits c_long"),
);
}
if errcode != 0 {
return Err(WrapperError::CoolProp(read_message(&buf)));
}
Ok(())
}
pub fn keyed_output(&self, param: OutputParam) -> Result<f64, WrapperError> {
let mut errcode: c_long = 0;
let mut buf = [0u8; MSG_BUF_LEN];
let _guard = COOLPROP_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
let value = unsafe {
ffi::AbstractState_keyed_output(
self.handle,
param.as_c_long(),
&raw mut errcode,
buf.as_mut_ptr().cast::<c_char>(),
c_long::try_from(MSG_BUF_LEN).expect("buffer length fits c_long"),
)
};
if errcode != 0 {
return Err(WrapperError::CoolProp(read_message(&buf)));
}
Ok(value)
}
}
impl Drop for AbstractState {
fn drop(&mut self) {
let mut errcode: c_long = 0;
let mut buf = [0u8; MSG_BUF_LEN];
let _guard = COOLPROP_LOCK
.lock()
.unwrap_or_else(std::sync::PoisonError::into_inner);
unsafe {
ffi::AbstractState_free(
self.handle,
&raw mut errcode,
buf.as_mut_ptr().cast::<c_char>(),
c_long::try_from(MSG_BUF_LEN).expect("buffer length fits c_long"),
);
}
}
}
unsafe impl Send for AbstractState {}
fn read_message(buf: &[u8]) -> String {
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
String::from_utf8_lossy(&buf[..end]).into_owned()
}