use crate::error::InchiError;
use std::ffi::{CStr, CString};
use std::os::raw::c_char;
use std::sync::{Mutex, MutexGuard};
static INCHI_LOCK: Mutex<()> = Mutex::new(());
pub(crate) fn lock() -> MutexGuard<'static, ()> {
match INCHI_LOCK.lock() {
Ok(guard) => guard,
Err(poisoned) => poisoned.into_inner(),
}
}
pub(crate) fn to_cstring(s: &str) -> Result<CString, InchiError> {
CString::new(s).map_err(|e| InchiError::InteriorNul {
position: e.nul_position(),
})
}
pub(crate) unsafe fn cstr_to_string(ptr: *const c_char) -> String {
if ptr.is_null() {
String::new()
} else {
CStr::from_ptr(ptr).to_string_lossy().into_owned()
}
}
pub(crate) struct OutputGuard {
raw: inchi_sys::inchi_Output,
}
impl OutputGuard {
pub(crate) fn new() -> Self {
OutputGuard {
raw: unsafe { std::mem::zeroed() },
}
}
pub(crate) fn as_mut_ptr(&mut self) -> *mut inchi_sys::inchi_Output {
&mut self.raw
}
pub(crate) fn inchi(&self) -> String {
unsafe { cstr_to_string(self.raw.szInChI) }
}
pub(crate) fn aux_info(&self) -> String {
unsafe { cstr_to_string(self.raw.szAuxInfo) }
}
pub(crate) fn message(&self) -> String {
unsafe { cstr_to_string(self.raw.szMessage) }
}
pub(crate) fn log(&self) -> String {
unsafe { cstr_to_string(self.raw.szLog) }
}
}
impl Drop for OutputGuard {
fn drop(&mut self) {
unsafe { inchi_sys::FreeINCHI(&mut self.raw) }
}
}