use crate::Value;
use ffi::FFI;
use std::ffi::CString;
use std::mem::MaybeUninit;
use std::os::raw::{c_char, c_void};
use std::path::Path;
pub struct WriteNTuples {
n: *mut sys::gsl_ntuple,
}
impl WriteNTuples {
#[doc(alias = "gsl_ntuple_create")]
pub fn create<P: AsRef<Path>>(filename: P) -> Option<WriteNTuples> {
let filename = filename.as_ref();
let filename = filename.to_str().expect("Failed to convert path to str");
let c_str = CString::new(filename.as_bytes()).unwrap();
let tmp = unsafe {
sys::gsl_ntuple_create(c_str.as_ptr() as *mut c_char, std::ptr::null_mut(), 0)
};
if tmp.is_null() {
None
} else {
Some(Self { n: tmp })
}
}
#[doc(alias = "gsl_ntuple_write")]
pub fn write<T: Sized>(&mut self, data: &T) -> Result<(), Value> {
let ret = unsafe {
(*self.n).ntuple_data = data as *const T as usize as *mut _;
(*self.n).size = std::mem::size_of::<T>() as _;
sys::gsl_ntuple_write(self.n)
};
result_handler!(ret, ())
}
#[doc(alias = "gsl_ntuple_bookdata")]
pub fn bookdata<T: Sized>(&mut self, data: &T) -> Result<(), Value> {
let ret = unsafe {
(*self.n).ntuple_data = data as *const T as usize as *mut _;
(*self.n).size = std::mem::size_of::<T>() as _;
sys::gsl_ntuple_bookdata(self.n)
};
result_handler!(ret, ())
}
}
impl Drop for WriteNTuples {
#[doc(alias = "gsl_ntuple_close")]
fn drop(&mut self) {
unsafe { sys::gsl_ntuple_close(self.n) };
}
}
pub struct ReadNTuples {
n: *mut sys::gsl_ntuple,
}
impl ReadNTuples {
#[doc(alias = "gsl_ntuple_open")]
pub fn open<P: AsRef<Path>>(filename: P) -> Option<ReadNTuples> {
let filename = filename.as_ref();
let filename = filename.to_str().expect("Failed to convert path to str");
let c_str = CString::new(filename.as_bytes()).unwrap();
let tmp =
unsafe { sys::gsl_ntuple_open(c_str.as_ptr() as *mut c_char, std::ptr::null_mut(), 0) };
if tmp.is_null() {
None
} else {
Some(Self { n: tmp })
}
}
#[doc(alias = "gsl_ntuple_read")]
pub fn read<T: Sized>(&mut self) -> Result<T, Value> {
let mut data = MaybeUninit::<T>::uninit();
let ret = unsafe {
(*self.n).ntuple_data = data.as_mut_ptr() as *mut _;
(*self.n).size = std::mem::size_of::<T>() as _;
sys::gsl_ntuple_read(self.n)
};
result_handler!(ret, unsafe { data.assume_init() })
}
}
impl Drop for ReadNTuples {
#[doc(alias = "gsl_ntuple_close")]
fn drop(&mut self) {
unsafe { sys::gsl_ntuple_close(self.n) };
}
}
macro_rules! impl_project {
($name:ident) => {
impl $name {
#[doc(alias = "gsl_ntuple_project")]
pub fn project<T: Sized, V: Fn(&T) -> f64, S: Fn(&T) -> bool>(
&self,
h: &mut ::Histogram,
value_func: V,
select_func: S,
) -> Result<(), Value> {
unsafe extern "C" fn value_trampoline<T: Sized, F: Fn(&T) -> f64>(
x: *mut c_void,
params: *mut c_void,
) -> f64 {
let f: &F = &*(params as *const F);
let x: &T = &*(x as *const T);
f(x)
}
unsafe extern "C" fn select_trampoline<T: Sized, F: Fn(&T) -> bool>(
x: *mut c_void,
params: *mut c_void,
) -> i32 {
let f: &F = &*(params as *const F);
let x: &T = &*(x as *const T);
if f(x) {
1
} else {
0
}
}
let f: Box<V> = Box::new(value_func);
let mut value_function = sys::gsl_ntuple_value_fn {
function: unsafe { std::mem::transmute(value_trampoline::<T, V> as usize) },
params: Box::into_raw(f) as *mut _,
};
let f: Box<S> = Box::new(select_func);
let mut select_function = sys::gsl_ntuple_select_fn {
function: unsafe { std::mem::transmute(select_trampoline::<T, S> as usize) },
params: Box::into_raw(f) as *mut _,
};
let ret = unsafe {
sys::gsl_ntuple_project(
h.unwrap_unique(),
self.n,
&mut value_function,
&mut select_function,
)
};
result_handler!(ret, ())
}
}
};
}
impl_project!(WriteNTuples);
impl_project!(ReadNTuples);