From 59d14d0a21cc110df5898d7d1f00f5693e76d28c Mon Sep 17 00:00:00 2001 From: Anthony Scemama Date: Tue, 10 Oct 2023 18:31:55 +0200 Subject: [PATCH] Creating rust binding --- rust/trexio/Cargo.toml | 12 +++ rust/trexio/build.py | 39 ++++++++++ rust/trexio/src/back_end.rs | 31 ++++++++ rust/trexio/src/c.rs | 6 ++ rust/trexio/src/exit_code.rs | 139 +++++++++++++++++++++++++++++++++++ rust/trexio/src/lib.rs | 109 +++++++++++++++++++++++++++ rust/trexio/src/main.rs | 13 ++++ rust/trexio/src/test.rs | 116 +++++++++++++++++++++++++++++ 8 files changed, 465 insertions(+) create mode 100644 rust/trexio/Cargo.toml create mode 100755 rust/trexio/build.py create mode 100644 rust/trexio/src/back_end.rs create mode 100644 rust/trexio/src/c.rs create mode 100644 rust/trexio/src/exit_code.rs create mode 100644 rust/trexio/src/lib.rs create mode 100644 rust/trexio/src/main.rs create mode 100644 rust/trexio/src/test.rs diff --git a/rust/trexio/Cargo.toml b/rust/trexio/Cargo.toml new file mode 100644 index 0000000..a2020e8 --- /dev/null +++ b/rust/trexio/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "trexio" +version = "2.4.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +bindgen = "0.65.1" + diff --git a/rust/trexio/build.py b/rust/trexio/build.py new file mode 100755 index 0000000..8e6aa89 --- /dev/null +++ b/rust/trexio/build.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +def main(): + err = {} + be = {} + with open("../../include/trexio.h", 'r') as f: + for line in f: + buf = line.lstrip() + + # Get exit codes + if buf.startswith("#define TREXIO_") and "(trexio_exit_code)" in buf : + buf2 = buf.replace(")","").replace("(","").split() + err[buf2[1]] = int(buf2[3].strip()) + + # Get backends + if buf.startswith("#define TREXIO_") and "(back_end_t)" in buf : + buf2 = buf.replace(")","").replace("(","").split() + be[buf2[1]] = int(buf2[3].strip()) + + with open("wrapper.h",'w') as f: + f.write("#include \n") + + # Write exit codes + for k, v in err.items(): + f.write(f"#undef {k}\n") + f.write(f"const trexio_exit_code {k} = {v};\n") + + # Write backends + for k, v in be.items(): + f.write(f"#undef {k}\n") + f.write(f"const back_end_t {k} = {v};\n") + + f.write(f"#undef TREXIO_AUTO;\n") + f.write(f"const back_end_t TREXIO_AUTO = TREXIO_INVALID_BACK_END;\n") + + + +if __name__ == '__main__': + main() diff --git a/rust/trexio/src/back_end.rs b/rust/trexio/src/back_end.rs new file mode 100644 index 0000000..15c981c --- /dev/null +++ b/rust/trexio/src/back_end.rs @@ -0,0 +1,31 @@ +use crate::c; + +/// Possible back ends +#[derive(Debug)] +pub enum BackEnd { + Text, + Hdf5, + Auto, +} + +impl BackEnd { + + /// Creation from a C value + pub fn from(b : c::back_end_t) -> Self { + match b { + c::TREXIO_TEXT => Self::Text, + c::TREXIO_HDF5 => Self::Hdf5, + c::TREXIO_AUTO => Self::Auto, + _ => panic!("Invalid backend"), + } + } + + /// Conversion to a C value + pub fn to_c(self) -> c::back_end_t { + match self { + Self::Text => c::TREXIO_TEXT, + Self::Hdf5 => c::TREXIO_HDF5, + Self::Auto => c::TREXIO_AUTO, + } + } +} diff --git a/rust/trexio/src/c.rs b/rust/trexio/src/c.rs new file mode 100644 index 0000000..cd503e4 --- /dev/null +++ b/rust/trexio/src/c.rs @@ -0,0 +1,6 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/rust/trexio/src/exit_code.rs b/rust/trexio/src/exit_code.rs new file mode 100644 index 0000000..d842d34 --- /dev/null +++ b/rust/trexio/src/exit_code.rs @@ -0,0 +1,139 @@ +use crate::c; + +/// Exit codes +#[derive(Debug)] +pub enum ExitCode { + Failure, + Success, + InvalidArg1, + InvalidArg2, + InvalidArg3, + InvalidArg4, + InvalidArg5, + End, + ReadOnly, + Errno, + InvalidId, + AllocationFailed, + HasNot, + InvalidNum, + AttrAlreadyExists, + DsetAlreadyExists, + OpenError, + LockError, + UnlockError, + FileError, + GroupReadError, + GroupWriteError, + ElemReadError, + ElemWriteError, + UnsafeArrayDim, + AttrMissing, + DsetMissing, + BackEndMissing, + InvalidArg6, + InvalidArg7, + InvalidArg8, + InvalidStrLen, + IntSizeOverflow, + SafeMode, + InvalidElectronNum, + InvalidDeterminantNum, + InvalidState, + VersionParsingIssue, + PhaseChange, +} + +impl ExitCode { + + /// Creation from a C value + pub fn from(rc : c::trexio_exit_code) -> Self { + match rc { + c::TREXIO_FAILURE => Self::Failure, + c::TREXIO_SUCCESS => Self::Success, + c::TREXIO_INVALID_ARG_1 => Self::InvalidArg1, + c::TREXIO_INVALID_ARG_2 => Self::InvalidArg2, + c::TREXIO_INVALID_ARG_3 => Self::InvalidArg3, + c::TREXIO_INVALID_ARG_4 => Self::InvalidArg4, + c::TREXIO_INVALID_ARG_5 => Self::InvalidArg5, + c::TREXIO_END => Self::End, + c::TREXIO_READONLY => Self::ReadOnly, + c::TREXIO_ERRNO => Self::Errno, + c::TREXIO_INVALID_ID => Self::InvalidId, + c::TREXIO_ALLOCATION_FAILED => Self::AllocationFailed, + c::TREXIO_HAS_NOT => Self::HasNot, + c::TREXIO_INVALID_NUM => Self::InvalidNum, + c::TREXIO_ATTR_ALREADY_EXISTS => Self::AttrAlreadyExists, + c::TREXIO_DSET_ALREADY_EXISTS => Self::DsetAlreadyExists, + c::TREXIO_OPEN_ERROR => Self::OpenError, + c::TREXIO_LOCK_ERROR => Self::LockError, + c::TREXIO_UNLOCK_ERROR => Self::UnlockError, + c::TREXIO_FILE_ERROR => Self::FileError, + c::TREXIO_GROUP_READ_ERROR => Self::GroupReadError, + c::TREXIO_GROUP_WRITE_ERROR => Self::GroupWriteError, + c::TREXIO_ELEM_READ_ERROR => Self::ElemReadError, + c::TREXIO_ELEM_WRITE_ERROR => Self::ElemWriteError, + c::TREXIO_UNSAFE_ARRAY_DIM => Self::UnsafeArrayDim, + c::TREXIO_ATTR_MISSING => Self::AttrMissing, + c::TREXIO_DSET_MISSING => Self::DsetMissing, + c::TREXIO_BACK_END_MISSING => Self::BackEndMissing, + c::TREXIO_INVALID_ARG_6 => Self::InvalidArg6, + c::TREXIO_INVALID_ARG_7 => Self::InvalidArg7, + c::TREXIO_INVALID_ARG_8 => Self::InvalidArg8, + c::TREXIO_INVALID_STR_LEN => Self::InvalidStrLen, + c::TREXIO_INT_SIZE_OVERFLOW => Self::IntSizeOverflow, + c::TREXIO_SAFE_MODE => Self::SafeMode, + c::TREXIO_INVALID_ELECTRON_NUM => Self::InvalidElectronNum, + c::TREXIO_INVALID_DETERMINANT_NUM => Self::InvalidDeterminantNum, + c::TREXIO_INVALID_STATE => Self::InvalidState, + c::TREXIO_VERSION_PARSING_ISSUE => Self::VersionParsingIssue, + c::TREXIO_PHASE_CHANGE => Self::PhaseChange, + _ => panic!("Unknown exit code"), + } + } + + /// Conversion to a C value + pub fn to_c(self) -> c::trexio_exit_code { + match self { + Self::Failure => c::TREXIO_FAILURE, + Self::Success => c::TREXIO_SUCCESS, + Self::InvalidArg1 => c::TREXIO_INVALID_ARG_1, + Self::InvalidArg2 => c::TREXIO_INVALID_ARG_2, + Self::InvalidArg3 => c::TREXIO_INVALID_ARG_3, + Self::InvalidArg4 => c::TREXIO_INVALID_ARG_4, + Self::InvalidArg5 => c::TREXIO_INVALID_ARG_5, + Self::End => c::TREXIO_END, + Self::ReadOnly => c::TREXIO_READONLY, + Self::Errno => c::TREXIO_ERRNO, + Self::InvalidId => c::TREXIO_INVALID_ID, + Self::AllocationFailed => c::TREXIO_ALLOCATION_FAILED, + Self::HasNot => c::TREXIO_HAS_NOT, + Self::InvalidNum => c::TREXIO_INVALID_NUM, + Self::AttrAlreadyExists => c::TREXIO_ATTR_ALREADY_EXISTS, + Self::DsetAlreadyExists => c::TREXIO_DSET_ALREADY_EXISTS, + Self::OpenError => c::TREXIO_OPEN_ERROR, + Self::LockError => c::TREXIO_LOCK_ERROR, + Self::UnlockError => c::TREXIO_UNLOCK_ERROR, + Self::FileError => c::TREXIO_FILE_ERROR, + Self::GroupReadError => c::TREXIO_GROUP_READ_ERROR, + Self::GroupWriteError => c::TREXIO_GROUP_WRITE_ERROR, + Self::ElemReadError => c::TREXIO_ELEM_READ_ERROR, + Self::ElemWriteError => c::TREXIO_ELEM_WRITE_ERROR, + Self::UnsafeArrayDim => c::TREXIO_UNSAFE_ARRAY_DIM, + Self::AttrMissing => c::TREXIO_ATTR_MISSING, + Self::DsetMissing => c::TREXIO_DSET_MISSING, + Self::BackEndMissing => c::TREXIO_BACK_END_MISSING, + Self::InvalidArg6 => c::TREXIO_INVALID_ARG_6, + Self::InvalidArg7 => c::TREXIO_INVALID_ARG_7, + Self::InvalidArg8 => c::TREXIO_INVALID_ARG_8, + Self::InvalidStrLen => c::TREXIO_INVALID_STR_LEN, + Self::IntSizeOverflow => c::TREXIO_INT_SIZE_OVERFLOW, + Self::SafeMode => c::TREXIO_SAFE_MODE, + Self::InvalidElectronNum => c::TREXIO_INVALID_ELECTRON_NUM, + Self::InvalidDeterminantNum => c::TREXIO_INVALID_DETERMINANT_NUM, + Self::InvalidState => c::TREXIO_INVALID_STATE, + Self::VersionParsingIssue => c::TREXIO_VERSION_PARSING_ISSUE, + Self::PhaseChange => c::TREXIO_PHASE_CHANGE, + } + } +} diff --git a/rust/trexio/src/lib.rs b/rust/trexio/src/lib.rs new file mode 100644 index 0000000..e89916b --- /dev/null +++ b/rust/trexio/src/lib.rs @@ -0,0 +1,109 @@ +use ::std::os::raw::c_char; + +/// C module generated by bindgen +pub mod c; + +/// Exit codes +pub mod exit_code; +pub use exit_code::ExitCode; + +/// Possible backends +pub mod back_end; +pub use back_end::BackEnd; + +/// Type for a TREXIO file +pub type File = *mut c::trexio_t; + +pub const PACKAGE_VERSION : &str = unsafe { std::str::from_utf8_unchecked(c::TREXIO_PACKAGE_VERSION) }; + +fn rc_return(rc : c::trexio_exit_code, result: T) -> Result { + let rc = ExitCode::from(rc); + match rc { + ExitCode::Success => Ok(result), + x => Err(x) + } +} + +fn file_name_to_c(file_name: &str) -> std::ffi::CString { + std::ffi::CString::new(file_name).unwrap() +} + + + + + +pub fn open(file_name: &str, mode: char, back_end: BackEnd) -> Result { + let file_name_c = file_name_to_c(file_name); + let file_name_c = file_name_c.as_ptr() as *const c_char; + let mode = mode as c_char; + let back_end = back_end.to_c(); + let rc: *mut c::trexio_exit_code = &mut c::TREXIO_SUCCESS.clone(); + let result = unsafe { c::trexio_open(file_name_c, mode, back_end, rc) }; + let rc = unsafe { *rc }; + rc_return(rc, result) +} + +pub fn close(file: File) -> Result<(), ExitCode> { + let rc = unsafe { c::trexio_close(file) }; + rc_return(rc, ()) +} + +pub fn inquire(file_name: &str) -> Result { + let file_name_c = file_name_to_c(file_name); + let file_name_c = file_name_c.as_ptr() as *const c_char; + let rc = unsafe { c::trexio_inquire(file_name_c) }; + match ExitCode::from(rc) { + ExitCode::Failure => Ok(false), + ExitCode::Success => Ok(true), + x => Err(x), + } +} + + +pub fn has_nucleus_num(trex_file: File) -> Result { + let rc = unsafe { c::trexio_has_nucleus_num(trex_file) }; + match rc { + c::TREXIO_SUCCESS => Ok(true), + c::TREXIO_HAS_NOT => Ok(false), + x => Err(ExitCode::from(x)), + } +} + +pub fn has_nucleus_charge(trex_file: File) -> Result { + let rc = unsafe { c::trexio_has_nucleus_charge(trex_file) }; + match rc { + c::TREXIO_SUCCESS => Ok(true), + c::TREXIO_HAS_NOT => Ok(false), + x => Err(ExitCode::from(x)), + } +} + + +pub fn write_nucleus_num(trex_file: File, data: usize) -> Result<(), ExitCode> { + let data: i64 = data.try_into().unwrap(); + let rc = unsafe { c::trexio_write_nucleus_num_64(trex_file, data) }; + rc_return(rc, ()) +} + +pub fn write_nucleus_charge(trex_file: File, data: Vec) -> Result<(), ExitCode> { + let size: i64 = data.len().try_into().unwrap(); + let rc = unsafe { c::trexio_write_safe_nucleus_charge_64(trex_file, data.as_ptr() as *const f64, size) }; + rc_return(rc, ()) +} + + + +#[cfg(test)] +mod tests { + use super::*; + use std::mem; + use c::*; + + #[test] + fn read_trexio_file() { + println!("============================================"); + println!(" TREXIO MAJOR VERSION : {}", TREXIO_VERSION_MAJOR); + println!("============================================"); + + } +} diff --git a/rust/trexio/src/main.rs b/rust/trexio/src/main.rs new file mode 100644 index 0000000..98fb1b2 --- /dev/null +++ b/rust/trexio/src/main.rs @@ -0,0 +1,13 @@ +mod test; + +fn main() { + println!("============================================"); + println!(" TREXIO VERSION : {}", trexio::PACKAGE_VERSION ); + println!("============================================"); + + let file_name = "test_write_rust.dir"; + + let back_end = trexio::BackEnd::Text; + test::test_write(file_name, back_end); + +} diff --git a/rust/trexio/src/test.rs b/rust/trexio/src/test.rs new file mode 100644 index 0000000..66d08fc --- /dev/null +++ b/rust/trexio/src/test.rs @@ -0,0 +1,116 @@ +use trexio::back_end::BackEnd; + +pub fn test_write(file_name: &str, back_end: BackEnd) { + + // Prepare data to be written + let n_buffers = 5; + let buf_size_sparse = 100/n_buffers; + let buf_size_det = 50/n_buffers; + let mut value_sparse_ao_2e_int_eri = vec![0.0f64 ; 100]; + let mut index_sparse_ao_2e_int_eri = vec![0i32 ; 400]; + for i in 0..100 { + let i : usize = i; + let j : i32 = i.try_into().unwrap(); + let fj : f64 = j.try_into().unwrap(); + value_sparse_ao_2e_int_eri[i] = 3.14 + fj; + index_sparse_ao_2e_int_eri[4*i + 0] = 4*j - 3; + index_sparse_ao_2e_int_eri[4*i + 1] = 4*j+1 - 3; + index_sparse_ao_2e_int_eri[4*i + 2] = 4*j+2 - 3; + index_sparse_ao_2e_int_eri[4*i + 3] = 4*j+3 - 3; + } + + let nucleus_num = 12; + let state_id = 2; + let charge = vec![6., 6., 6., 6., 6., 6., 1., 1., 1., 1., 1., 1.0f64]; + let coord = vec![ 0.00000000, 1.39250319 , 0.00 , + -1.20594314, 0.69625160 , 0.00 , + -1.20594314, -0.69625160 , 0.00 , + 0.00000000, -1.39250319 , 0.00 , + 1.20594314, -0.69625160 , 0.00 , + 1.20594314, 0.69625160 , 0.00 , + -2.14171677, 1.23652075 , 0.00 , + -2.14171677, -1.23652075 , 0.00 , + 0.00000000, -2.47304151 , 0.00 , + 2.14171677, -1.23652075 , 0.00 , + 2.14171677, 1.23652075 , 0.00 , + 0.00000000, 2.47304151 , 0.00 ]; + let mo_num = 150; + let ao_num = 1000; + let basis_shell_num = 24; + let basis_nucleus_index = vec!([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 ]); + + let label = vec![ + "C ", + "Na ", + "C ", + "C 66 ", + "C ", + "C ", + "H 99 ", + "Ru ", + "H ", + "H ", + "H ", + "H " ]; + let mut label = label.concat(); + let sym_str = b"B3U with some comments"; + + + println!("{}", file_name); + assert!( ! trexio::inquire(file_name).unwrap() ); + + let trex_file = trexio::open(file_name, 'w', back_end).unwrap(); + + assert( ! trexio::has_nucleus_num(trex_file).unwrap() ); + assert( ! trexio::has_nucleus_charge(trex_file).unwrap() ); + +/* + let rc = unsafe { trexio_has_ao_2e_int_eri(trex_file) }; + assert!(rc == TREXIO_HAS_NOT); + + let rc = unsafe { trexio_has_determinant_list(trex_file) }; + assert!(rc == TREXIO_HAS_NOT); + + let rc = unsafe { trexio_has_nucleus(trex_file) }; + assert!(rc == TREXIO_HAS_NOT); + + let rc = unsafe { trexio_has_ao_2e_int(trex_file) }; + assert!(rc == TREXIO_HAS_NOT); + */ + + trexio::write_nucleus_num(trex_file, nucleus_num).unwrap(); + trexio::write_nucleus_charge(trex_file, charge).unwrap(); + +/* + let rc = unsafe { trexio_write_nucleus_coord(trex_file, coord.as_ptr() as *const f64) }; + assert!(rc == TREXIO_SUCCESS); + + let rc = unsafe { trexio_write_nucleus_label(trex_file, label.as_ptr(), label[0].len().try_into().unwrap()) }; + assert!(rc == TREXIO_SUCCESS); + + let rc = unsafe { trexio_write_nucleus_point_group(trex_file, sym_str.as_ptr() as *const i8, sym_str.len().try_into().unwrap()) }; + assert!(rc == TREXIO_SUCCESS); + + let rc = unsafe { trexio_write_basis_shell_num(trex_file, basis_shell_num) }; + assert!(rc == TREXIO_SUCCESS); + + let rc = unsafe { trexio_write_basis_nucleus_index(trex_file, basis_nucleus_index.as_ptr() as *const i32) }; + assert!(rc == TREXIO_SUCCESS); + + let rc = unsafe { trexio_write_state_id(trex_file, state_id) }; + assert!(rc == TREXIO_SUCCESS); + + if (unsafe { trexio_has_ao_num(trex_file) } == TREXIO_HAS_NOT) { + let rc = unsafe { trexio_write_ao_num(trex_file, ao_num) }; + assert!(rc == TREXIO_SUCCESS); + } + + if (unsafe { trexio_has_mo_num(trex_file) } == TREXIO_HAS_NOT) { + let rc = unsafe { trexio_write_mo_num(trex_file, mo_num) }; + assert!(rc == TREXIO_SUCCESS); + } + */ + + trexio::close(trex_file).expect("Unable to close File"); + +}