1
0
mirror of https://github.com/TREX-CoE/trexio.git synced 2024-12-23 04:43:57 +01:00

Creating rust binding

This commit is contained in:
Anthony Scemama 2023-10-10 18:31:55 +02:00
parent 537bb19db9
commit 59d14d0a21
8 changed files with 465 additions and 0 deletions

12
rust/trexio/Cargo.toml Normal file
View File

@ -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"

39
rust/trexio/build.py Executable file
View File

@ -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 <trexio.h>\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()

View File

@ -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,
}
}
}

6
rust/trexio/src/c.rs Normal file
View File

@ -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"));

View File

@ -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,
}
}
}

109
rust/trexio/src/lib.rs Normal file
View File

@ -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<T>(rc : c::trexio_exit_code, result: T) -> Result<T,ExitCode> {
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<File, ExitCode> {
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<bool, ExitCode> {
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<bool, ExitCode> {
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<bool, ExitCode> {
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<f64>) -> 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!("============================================");
}
}

13
rust/trexio/src/main.rs Normal file
View File

@ -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);
}

116
rust/trexio/src/test.rs Normal file
View File

@ -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");
}