diff --git a/rust/trexio/build.py b/rust/trexio/build.py index 43931b7..5d8af25 100755 --- a/rust/trexio/build.py +++ b/rust/trexio/build.py @@ -86,12 +86,22 @@ def make_functions(): use std::iter::zip; use std::ffi::CString; +/// This implementation block includes additional functions automatically generated from tables. +/// For more details, refer to [TREXIO tables documentation](https://trex-coe.github.io/trexio/trex.html). impl File {""" ] for group in data: group_l = group.lower() r += [ """ /// Checks if the group `{group}` exists in the file. +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// * `Result` - Returns `Ok(true)` if the element exists in the file, +/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`. pub fn has_{group_l}(&self) -> Result { let rc = unsafe { c::trexio_has_{group}(self.ptr) }; match rc { @@ -109,6 +119,15 @@ pub fn has_{group_l}(&self) -> Result { element_l = element.lower() r += [ """ /// Checks if the element `{element}` of the group `{group}` exists in the file. +/// +/// # Parameters +/// +/// None +/// +/// # Returns +/// +/// * `Result` - Returns `Ok(true)` if the element exists in the file, +/// otherwise returns `Ok(false)`. An error during the execution results in `Err(ExitCode)`. pub fn has_{group_l}_{element_l}(&self) -> Result { let rc = unsafe { c::trexio_has_{group}_{element}(self.ptr) }; match rc { @@ -207,24 +226,33 @@ pub fn read_{group_l}_{element_l}(&self) -> Result<{type_r}, ExitCode> { if data[group][element][0] in [ "int", "float", "dim", "index" ]: t = [ f""" -/// Reads the array `{element}` contained in the group `{group}`. +/// Reads the `{element}` array from the group `{group}` in the file. +/// +/// # Dimensions +/// +/// The array is of dimension `{data[group][element][1]}`. +/// +/// # Returns +/// +/// * `Result, ExitCode>` - Returns a flattened one-dimensional vector that contains +/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`. /// -/// Dimensions are `{data[group][element][1]}`. /// """ ] if len(data[group][element][1]) > 1: - t += [ f"""/// The array is returned as a flattened one-dimensional vector. -/// To put it back as a multidimensional array, you can use the [`chunks`] method: + t += [ f""" +/// # Example +/// +/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method: /// -/// # Example /// ``` /// let one_d_array = trexio_file.read_{group_l}_{element_l}()?;""" ] try: dim_group, dim_element = data[group][element][1][0].split('.') t += [ f"/// let {dim_group}_{dim_element} = trexio_file.read_{dim_group}_{dim_element}()?;", -f"/// let two_d_array = one_d_array.chunks({dim_group}_{dim_element}).collect();" +f"/// let two_d_array: Vec<_> = one_d_array.chunks({dim_group}_{dim_element}).collect();" ] except: - t += [ f"/// let two_d_array = one_d_array.chunks({data[group][element][1][0]}).collect();" ] + t += [ f"/// let two_d_array: Vec<_> = one_d_array.chunks({data[group][element][1][0]}).collect();" ] t += [ """ /// ``` /// @@ -260,7 +288,19 @@ pub fn read_{group_l}_{element_l}(&self) -> Result, ExitCode> { .replace("{element}",element) .replace("{element_l}",element_l) ] - r += [ """ + r += [ f""" +/// Writes the `{element}` array into the group `{group}` in the file. +/// +/// # Parameters +/// +/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array +/// to be written into the file. The vector should be flattened from a two-dimensional array with +/// dimensions `{data[group][element][1]}`. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, +/// otherwise returns `Err(ExitCode)`.""", """\ pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitCode> { let size: i64 = data.len().try_into().expect("try_into failed in write_{group_l}_{element_l}"); let data = data.as_ptr() as *const {type_c}; @@ -276,7 +316,40 @@ pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitC .replace("{element_l}",element_l) ] elif data[group][element][0] in [ "str" ]: - t = [ """pub fn read_{group_l}_{element_l}(&self, capacity: usize) -> Result, ExitCode> { + t = [ f""" +/// Reads the `{element}` array from the group `{group}` in the file. +/// +/// # Dimensions +/// +/// The array is of dimension `{data[group][element][1]}`. +/// +/// # Returns +/// +/// * `Result, ExitCode>` - Returns a flattened one-dimensional vector that contains +/// the elements of the `{element}` array. If the operation is unsuccessful, it returns `Err(ExitCode)`. +/// +/// """ ] + if len(data[group][element][1]) > 1: + t += [ f""" +/// # Example +/// +/// To reshape the one-dimensional vector back into a two-dimensional array, you can use the [`chunks`] method: +/// +/// ``` +/// let one_d_array = trexio_file.read_{group_l}_{element_l}()?;""" ] + try: + dim_group, dim_element = data[group][element][1][0].split('.') + t += [ f"/// let {dim_group}_{dim_element} = trexio_file.read_{dim_group}_{dim_element}()?;", +f"/// let two_d_array: Vec<_> = one_d_array.chunks({dim_group}_{dim_element}).collect();" +] + except: + t += [ f"/// let two_d_array: Vec<_> = one_d_array.chunks({data[group][element][1][0]}).collect();" ] + t += [ """ +/// ``` +/// +/// [`chunks`]: slice::chunks""" +] + t += [ """pub fn read_{group_l}_{element_l}(&self, capacity: usize) -> Result, ExitCode> { let size = 1;""" ] t_prime = [] for dim in data[group][element][1]: @@ -330,6 +403,18 @@ pub fn write_{group_l}_{element_l}(&self, data: &[{type_r}]) -> Result<(), ExitC .replace("{element_l}",element_l) ] r += [ """ +/// Writes the `{element}` array into the group `{group}` in the file. +/// +/// # Parameters +/// +/// * `data: &[{type_r}]` - A one-dimensional vector that contains the elements of the `{element}` array +/// to be written into the file. The vector should be flattened from a two-dimensional array with +/// dimensions `{data[group][element][1]}`. +/// +/// # Returns +/// +/// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, +/// otherwise returns `Err(ExitCode)`.""", """\ pub fn write_{group_l}_{element_l}(&self, data: &[&str]) -> Result<(), ExitCode> { let mut size = 0; // Find longest string @@ -355,6 +440,7 @@ pub fn write_{group_l}_{element_l}(&self, data: &[&str]) -> Result<(), ExitCode> size = len(data[group][element][1]) typ = "(" + ",".join( [ "usize" for _ in range(size) ]) + ", f64)" r += [ (""" +// TODO pub fn read_{group_l}_{element_l}(&self, offset: usize, buffer_size:usize) -> Result, ExitCode> { let mut idx = Vec::::with_capacity({size}*buffer_size); let mut val = Vec::::with_capacity(buffer_size); @@ -393,6 +479,7 @@ pub fn read_{group_l}_{element_l}(&self, offset: usize, buffer_size:usize) -> Re .replace("{element_l}",element_l) ] r += [ (""" +// TODO pub fn write_{group_l}_{element_l}(&self, offset: usize, data: &[{typ}]) -> Result<(), ExitCode> { let mut idx = Vec::::with_capacity({size}*data.len()); let mut val = Vec::::with_capacity(data.len()); diff --git a/rust/trexio/src/lib.rs b/rust/trexio/src/lib.rs index 89292cb..986bb3e 100644 --- a/rust/trexio/src/lib.rs +++ b/rust/trexio/src/lib.rs @@ -1,23 +1,34 @@ +/// TREXIO is an open-source file format and library developed for the storage and manipulation of +/// data produced by quantum chemistry calculations. It was designed with the goal of providing a +/// reliable and efficient method of storing and exchanging wave function parameters and matrix +/// elements. +/// +/// For comprehensive documentation, consult: [TREXIO Documentation](https://trex-coe.github.io/trexio/) +/// +/// The C library source code is available on GitHub: [TREXIO GitHub Repository](https://github.com/trex-coe/trexio) +/// + use ::std::os::raw::c_char; -/// C module generated by bindgen mod c; -/// Errors returned by function calls. These are related to the exit codes defined in the C TREXIO library. -mod exit_code; +/// Enumeration representing the various error codes that might be returned by function calls. +/// These error codes are mapped to those defined in the original C TREXIO library. +pub mod exit_code; pub use exit_code::ExitCode; -/// Backends handled by TREXIO +/// Enum representing the different backends that TREXIO can employ for data storage. pub mod back_end; pub use back_end::BackEnd; -/// Bit fields, used for the description of determinants +/// Structure representing bit fields. Mainly utilized for encapsulating determinant descriptions. pub mod bitfield; pub use bitfield::Bitfield; -/// Version of the C TREXIO library +/// A constant string representing the package version of the linked C TREXIO library. pub const PACKAGE_VERSION : &str = unsafe { std::str::from_utf8_unchecked(c::TREXIO_PACKAGE_VERSION) }; +/// Utility function to convert Rust results into TREXIO exit codes. fn rc_return(result: T, rc : c::trexio_exit_code) -> Result { let rc = ExitCode::from(rc); match rc { @@ -26,19 +37,20 @@ fn rc_return(result: T, rc : c::trexio_exit_code) -> Result { } } +/// Utility function to convert Rust string to C-compatible string. fn string_to_c(s: &str) -> std::ffi::CString { std::ffi::CString::new(s).unwrap() } -/// Prints to standard output information about the C TREXIO library +/// Function to print out diagnostic information about the linked C TREXIO library. pub fn info() -> Result<(),ExitCode> { let rc = unsafe { c::trexio_info() }; rc_return((), rc) } -/// Type for a TREXIO file +/// Type representing a TREXIO file. Wraps a pointer to the underlying C structure. pub struct File { ptr: *mut c::trexio_t, } @@ -46,6 +58,16 @@ pub struct File { impl File { + /// Opens a TREXIO file. Returns a `File` instance that can be used for subsequent I/O operations. + /// + /// # Parameters + /// - `file_name`: The path to the TREXIO file. + /// - `mode`: Specifies the file access mode. `'r'` for read-only, `'w'` for safe write (write + /// if the data doesn't exist), `'u'` for unsafe write (update existing data). + /// - `back_end`: Specifies the backend used for data storage. + /// + /// # Returns + /// - `Result`: `File` instance or an error code. pub fn open(file_name: &str, mode: char, back_end: BackEnd) -> Result { let file_name_c = string_to_c(file_name); let file_name_c = file_name_c.as_ptr() as *const c_char; @@ -57,11 +79,27 @@ impl File { rc_return(File { ptr: result }, rc) } + /// Closes the current TREXIO file and releases associated resources. + /// + /// # Returns + /// - `Result<(), ExitCode>`: An error code in case of failure. pub fn close(self) -> Result<(), ExitCode> { let rc = unsafe { c::trexio_close(self.ptr) }; rc_return((), rc) } + + /// Inquires if a file with the specified name exists. + /// + /// # Parameters + /// + /// * `file_name: &str` - The name of the file to inquire about. + /// + /// # Returns + /// + /// * `Result` - Returns `Ok(true)` if the file exists, + /// `Ok(false)` otherwise. Returns `Err(ExitCode)` if an error occurs + /// during the operation. pub fn inquire(file_name: &str) -> Result { let file_name_c = string_to_c(file_name); let file_name_c = file_name_c.as_ptr() as *const c_char; @@ -73,6 +111,16 @@ impl File { } } + /// Retrieves the ID of the electronic state stored in the file. + /// + /// # Parameters + /// + /// None + /// + /// # Returns + /// + /// * `Result` - Returns the ID as `Ok(usize)` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. pub fn get_state(&self) -> Result { let mut num = 0i32; let rc = unsafe { c::trexio_get_state(self.ptr, &mut num) }; @@ -80,17 +128,33 @@ impl File { rc_return(result, rc) } + /// Sets the ID of the electronic state to be stored in the file. + /// + /// # Parameters + /// + /// * `num: usize` - The ID of the electronic state. + /// + /// # Returns + /// + /// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. pub fn set_state(&self, num: usize) -> Result<(), ExitCode> { let num: i32 = num.try_into().expect("try_into failed in set_state"); let rc = unsafe { c::trexio_set_state(self.ptr, num) }; rc_return((), rc) } - pub fn set_one_based(&self) -> Result<(), ExitCode> { - let rc = unsafe { c::trexio_set_one_based(self.ptr) }; - rc_return((), rc) - } - + /// Retrieves the number of `i64` required to store a determinant as a bit-field. + /// This corresponds to \(\frac{\text{mo\_num}}{64}+1\). + /// + /// # Parameters + /// + /// None + /// + /// # Returns + /// + /// * `Result` - Returns the number of `i64` as `Ok(usize)` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. pub fn get_int64_num(&self) -> Result { let mut num = 0i32; let rc = unsafe { @@ -100,15 +164,26 @@ impl File { rc_return(num, rc) } - pub fn write_determinant_list(&self, offset_file: usize, determinants: &[Bitfield]) -> Result<(), ExitCode> { + /// Writes a vector of determinants, represented as [Bitfield] objects. + /// + /// # Parameters + /// + /// * `offset: usize` - The number of determinants to skip in the file before writing. + /// * `determinants: &[Bitfield]` - The array of determinants to write. + /// + /// # Returns + /// + /// * `Result<(), ExitCode>` - Returns `Ok(())` if the operation is successful, + /// otherwise returns `Err(ExitCode)`. + pub fn write_determinant_list(&self, offset: usize, determinants: &[Bitfield]) -> Result<(), ExitCode> { let n_int = self.get_int64_num()?; match determinants.len() { 0 => return Ok(()), _ => if determinants[0].as_vec().len() != 2*n_int { - panic!("Inconsistent values of n_int") + return Err(exit_code::Invalid_Arg(3)) } }; - let offset_file: i64 = offset_file.try_into().expect("try_into failed in write_determinant_list"); + let offset: i64 = offset.try_into().expect("try_into failed in write_determinant_list"); let buffer_size: i64 = determinants.len().try_into().expect("try_into failed in write_determinant_list"); let mut one_d_array: Vec = Vec::with_capacity(determinants.len() * n_int); for det in determinants.iter() { @@ -118,19 +193,30 @@ impl File { } let dset: *const i64 = one_d_array.as_ptr() as *const i64; let rc = unsafe { - c::trexio_write_determinant_list(self.ptr, offset_file, buffer_size, dset) + c::trexio_write_determinant_list(self.ptr, offset, buffer_size, dset) }; rc_return((), rc) } - pub fn read_determinant_list(&self, offset_file: usize, buffer_size: usize) -> Result, ExitCode> { + /// Reads a vector of determinants, represented as [Bitfield] objects. + /// + /// # Parameters + /// + /// * `offset: usize` - The number of determinants to skip in the file before reading. + /// * `buffer_size: usize` - The number of determinants to read. + /// + /// # Returns + /// + /// * `Result, ExitCode>` - Returns the read determinants as `Ok(Vec)` + /// if the operation is successful, otherwise returns `Err(ExitCode)`. + pub fn read_determinant_list(&self, offset: usize, buffer_size: usize) -> Result, ExitCode> { let n_int = self.get_int64_num()?; let mut one_d_array: Vec = Vec::with_capacity(buffer_size * 2* n_int); let one_d_array_ptr = one_d_array.as_ptr() as *mut i64; let rc = unsafe { - let offset_file: i64 = offset_file.try_into().expect("try_into failed in read_determinant_list (offset_file)"); + let offset: i64 = offset.try_into().expect("try_into failed in read_determinant_list (offset)"); let mut buffer_size_read: i64 = buffer_size.try_into().expect("try_into failed in read_determinant_list (buffer_size)"); - let rc = c::trexio_read_determinant_list(self.ptr, offset_file, &mut buffer_size_read, one_d_array_ptr); + let rc = c::trexio_read_determinant_list(self.ptr, offset, &mut buffer_size_read, one_d_array_ptr); let buffer_size_read: usize = buffer_size_read.try_into().expect("try_into failed in read_determinant_list (buffer_size)"); one_d_array.set_len(n_int*2usize*buffer_size_read); match ExitCode::from(rc) { @@ -149,6 +235,8 @@ impl File { } +/// Inclusion of additional functions automatically generated from tables. +/// For more details, refer to [TREXIO tables documentation](https://trex-coe.github.io/trexio/trex.html). include!("generated.rs");