Merge pull request #1 from Yoshanuikabundi/remove-failure

Remove failure
This commit is contained in:
Daniel Bauer
2020-11-07 11:53:07 +01:00
committed by GitHub
10 changed files with 275 additions and 193 deletions

View File

@@ -8,7 +8,6 @@ description = "Wrapper around the gromacs libxdrfile library. Can be used to rea
build = "build.rs" build = "build.rs"
[dependencies] [dependencies]
failure = "0.1"
lazy-init = "0.3" lazy-init = "0.3"
[dev-dependencies] [dev-dependencies]

View File

@@ -1,5 +1,6 @@
#[allow(non_upper_case_globals)] #![allow(non_upper_case_globals, non_camel_case_types)]
pub mod xdr_seek;
pub mod xdrfile; pub mod xdrfile;
pub mod xdrfile_trr; pub mod xdrfile_trr;
pub mod xdrfile_xtc; pub mod xdrfile_xtc;
pub mod xdr_seek;

View File

@@ -103,12 +103,11 @@ extern "C" {
pub fn xdr_flush(xd: *mut XDRFILE) -> ::std::os::raw::c_int; pub fn xdr_flush(xd: *mut XDRFILE) -> ::std::os::raw::c_int;
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*;
use super::super::xdrfile_xtc::*; use super::super::xdrfile_xtc::*;
use super::*;
use std::ffi::CString; use std::ffi::CString;
#[test] #[test]
@@ -119,8 +118,8 @@ mod tests {
let mut step: i32 = 5; let mut step: i32 = 5;
let box_vec = [[0.0; 3]; 3]; let box_vec = [[0.0; 3]; 3];
let x_p = std::ptr::null_mut(); let x_p = std::ptr::null_mut();
let mut prec: f32 = 0.0; let mut prec: f32 = 0.0;
unsafe { unsafe {
let mode = CString::new("r").unwrap(); let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr());
@@ -129,20 +128,25 @@ mod tests {
let tell = xdr_tell(xdr); let tell = xdr_tell(xdr);
assert!(tell == 0, "{}", tell); assert!(tell == 0, "{}", tell);
read_xtc(xdr, num_atoms, &mut step, &mut time, read_xtc(
xdr,
num_atoms,
&mut step,
&mut time,
box_vec.as_ptr() as *mut Matrix, box_vec.as_ptr() as *mut Matrix,
x_p, x_p,
&mut prec); &mut prec,
);
let tell = xdr_tell(xdr); let tell = xdr_tell(xdr);
assert!(tell > 0, "{}", tell); assert!(tell > 0, "{}", tell);
} }
} }
#[test] #[test]
fn test_xdr_seek() { fn test_xdr_seek() {
let path = CString::new("tests/1l2y.xtc").unwrap(); let path = CString::new("tests/1l2y.xtc").unwrap();
unsafe { unsafe {
let mode = CString::new("r").unwrap(); let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(path.as_ptr(), mode.as_ptr());
@@ -152,9 +156,9 @@ mod tests {
assert!(tell == 0, "{}", tell); assert!(tell == 0, "{}", tell);
xdr_seek(xdr, 500, 0); xdr_seek(xdr, 500, 0);
let tell = xdr_tell(xdr); let tell = xdr_tell(xdr);
assert!(tell == 500, "{}", tell); assert!(tell == 500, "{}", tell);
} }
} }
} }

View File

@@ -1,4 +1,3 @@
pub const DIM: u32 = 3; pub const DIM: u32 = 3;
#[repr(C)] #[repr(C)]
@@ -7,7 +6,6 @@ pub struct XDRFILE {
_unused: [u8; 0], _unused: [u8; 0],
} }
pub type BindgenTy1 = u32; pub type BindgenTy1 = u32;
pub const exdrOK: BindgenTy1 = 0; pub const exdrOK: BindgenTy1 = 0;
pub const exdrHEADER: BindgenTy1 = 1; pub const exdrHEADER: BindgenTy1 = 1;

View File

@@ -1,6 +1,5 @@
use super::xdrfile::*; use super::xdrfile::*;
extern "C" { extern "C" {
pub fn read_trr_natoms( pub fn read_trr_natoms(
fn_: *const ::std::os::raw::c_char, fn_: *const ::std::os::raw::c_char,
@@ -10,7 +9,7 @@ extern "C" {
extern "C" { extern "C" {
pub fn read_trr_nframes( pub fn read_trr_nframes(
fn_: *const ::std::os::raw::c_char, fn_: *const ::std::os::raw::c_char,
nframes: *const ::std::os::raw::c_ulong, nframes: *const ::std::os::raw::c_ulong,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
@@ -61,7 +60,7 @@ mod tests {
#[test] #[test]
fn test_read_trr_nframes() { fn test_read_trr_nframes() {
let path = CString::new("tests/1l2y.trr").unwrap(); let path = CString::new("tests/1l2y.trr").unwrap();
let mut nframes: u64 = 0; let mut nframes: u64 = 0;
unsafe { unsafe {
let code = read_trr_nframes(path.as_ptr() as *const i8, &mut nframes); let code = read_trr_nframes(path.as_ptr() as *const i8, &mut nframes);
@@ -83,19 +82,25 @@ mod tests {
let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]]; let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]];
let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
let v: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; let v: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
let f: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; let f: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
unsafe { unsafe {
let mode = CString::new("w").unwrap(); let mode = CString::new("w").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let write_code = write_trr(xdr, natoms, step, time, lambda, let write_code = write_trr(
xdr,
natoms,
step,
time,
lambda,
box_vec.as_ptr() as *mut Matrix, box_vec.as_ptr() as *mut Matrix,
x.as_ptr() as *mut Rvec, x.as_ptr() as *mut Rvec,
v.as_ptr() as *mut Rvec, v.as_ptr() as *mut Rvec,
f.as_ptr() as *mut Rvec); f.as_ptr() as *mut Rvec,
);
assert!(write_code as u32 == exdrOK); assert!(write_code as u32 == exdrOK);
xdrfile_close(xdr); xdrfile_close(xdr);
} }
// read atoms from tempfile // read atoms from tempfile
@@ -111,13 +116,19 @@ mod tests {
unsafe { unsafe {
let mode = CString::new("r").unwrap(); let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let read_code = read_trr(xdr, natoms, &mut step2, &mut time2, let read_code = read_trr(
&mut lambda2, box_vec2.as_ptr() as *mut Matrix, xdr,
natoms,
&mut step2,
&mut time2,
&mut lambda2,
box_vec2.as_ptr() as *mut Matrix,
x2.as_ptr() as *mut Rvec, x2.as_ptr() as *mut Rvec,
v2.as_ptr() as *mut Rvec, v2.as_ptr() as *mut Rvec,
f2.as_ptr() as *mut Rvec); f2.as_ptr() as *mut Rvec,
);
assert!(read_code as u32 == exdrOK); assert!(read_code as u32 == exdrOK);
xdrfile_close(xdr); xdrfile_close(xdr);
} }
// make sure everything is still the same // make sure everything is still the same
@@ -129,5 +140,4 @@ mod tests {
assert!(v2 == v); assert!(v2 == v);
assert!(f2 == f); assert!(f2 == f);
} }
}
}

View File

@@ -1,6 +1,5 @@
use super::xdrfile::*; use super::xdrfile::*;
extern "C" { extern "C" {
pub fn read_xtc_natoms( pub fn read_xtc_natoms(
fn_: *const ::std::os::raw::c_char, fn_: *const ::std::os::raw::c_char,
@@ -10,7 +9,7 @@ extern "C" {
extern "C" { extern "C" {
pub fn read_xtc_nframes( pub fn read_xtc_nframes(
fn_: *const ::std::os::raw::c_char, fn_: *const ::std::os::raw::c_char,
nframes: *const ::std::os::raw::c_ulong, nframes: *const ::std::os::raw::c_ulong,
) -> ::std::os::raw::c_int; ) -> ::std::os::raw::c_int;
} }
extern "C" { extern "C" {
@@ -57,7 +56,7 @@ mod tests {
#[test] #[test]
fn test_read_xtc_nframes() { fn test_read_xtc_nframes() {
let path = CString::new("tests/1l2y.xtc").unwrap(); let path = CString::new("tests/1l2y.xtc").unwrap();
let mut nframes: u64 = 0; let mut nframes: u64 = 0;
unsafe { unsafe {
let code = read_xtc_nframes(path.as_ptr() as *const i8, &mut nframes); let code = read_xtc_nframes(path.as_ptr() as *const i8, &mut nframes);
@@ -77,15 +76,21 @@ mod tests {
let step: i32 = 5; let step: i32 = 5;
let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]]; let box_vec: Matrix = [[1.0, 2.0, 3.0], [2.0, 1.0, 3.0], [3.0, 2.0, 1.0]];
let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]]; let x: Vec<Rvec> = vec![[1.0, 1.0, 1.0], [1.0, 1.0, 1.0]];
unsafe { unsafe {
let mode = CString::new("w").unwrap(); let mode = CString::new("w").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let write_code = write_xtc(xdr, natoms, step, time, let write_code = write_xtc(
box_vec.as_ptr() as *mut Matrix, x.as_ptr() as *mut Rvec, xdr,
1000.0); natoms,
step,
time,
box_vec.as_ptr() as *mut Matrix,
x.as_ptr() as *mut Rvec,
1000.0,
);
assert!(write_code as u32 == exdrOK); assert!(write_code as u32 == exdrOK);
xdrfile_close(xdr); xdrfile_close(xdr);
} }
// read atoms from tempfile // read atoms from tempfile
@@ -98,11 +103,17 @@ mod tests {
unsafe { unsafe {
let mode = CString::new("r").unwrap(); let mode = CString::new("r").unwrap();
let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr()); let xdr = xdrfile_open(tmp_path.as_ptr(), mode.as_ptr());
let read_code = read_xtc(xdr, natoms, &mut step2, &mut time2, let read_code = read_xtc(
box_vec2.as_ptr() as *mut Matrix, x2.as_ptr() as *mut Rvec, xdr,
&mut prec); natoms,
&mut step2,
&mut time2,
box_vec2.as_ptr() as *mut Matrix,
x2.as_ptr() as *mut Rvec,
&mut prec,
);
assert!(read_code as u32 == exdrOK); assert!(read_code as u32 == exdrOK);
xdrfile_close(xdr); xdrfile_close(xdr);
} }
// make sure everything is still the same // make sure everything is still the same
@@ -111,4 +122,4 @@ mod tests {
assert!(box_vec2 == box_vec); assert!(box_vec2 == box_vec);
assert!(x2 == x); assert!(x2 == x);
} }
} }

View File

@@ -12,68 +12,72 @@ pub struct Frame {
/// Time step (usually in picoseconds) /// Time step (usually in picoseconds)
pub time: f32, pub time: f32,
/// 3x3 box vector /// 3x3 box vector
pub box_vector: [[f32; 3usize]; 3usize], pub box_vector: [[f32; 3usize]; 3usize],
/// 3D coordinates for N atoms where N is num_atoms /// 3D coordinates for N atoms where N is num_atoms
pub coords: Vec<[f32; 3usize]>, pub coords: Vec<[f32; 3usize]>,
} }
impl Default for Frame { impl Default for Frame {
fn default() -> Frame { fn default() -> Frame {
Frame { Frame {
num_atoms: 0, num_atoms: 0,
step: 0, step: 0,
time: 0.0, time: 0.0,
box_vector: [[0.0; 3]; 3], box_vector: [[0.0; 3]; 3],
coords: Vec::with_capacity(0) coords: Vec::with_capacity(0),
} }
} }
} }
impl fmt::Debug for Frame { impl fmt::Debug for Frame {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Frame {{ atoms: {}, step: {}, time: {}, \ write!(
box: {:?}, coords: {:?} }}", self.num_atoms, self.step, self.time, f,
self.box_vector, self.coords) "Frame {{ atoms: {}, step: {}, time: {}, \
box: {:?}, coords: {:?} }}",
self.num_atoms, self.step, self.time, self.box_vector, self.coords
)
} }
} }
impl Frame { impl Frame {
/// Creates an empty frame with a capacity of 0 /// Creates an empty frame with a capacity of 0
pub fn new() -> Frame { pub fn new() -> Frame {
Frame{ ..Default::default() } Frame {
..Default::default()
}
} }
/// Creates a frame with the given capacity /// Creates a frame with the given capacity
pub fn with_capacity(num_atoms: u32) -> Frame { pub fn with_capacity(num_atoms: u32) -> Frame {
Frame { Frame {
num_atoms: num_atoms, num_atoms,
coords: vec![[0.0, 0.0, 0.0]; num_atoms as usize], coords: vec![[0.0, 0.0, 0.0]; num_atoms as usize],
..Default::default() ..Default::default()
} }
} }
/// Filters the frame by removing all atoms not matching the given indeces. /// Filters the frame by removing all atoms not matching the given indeces.
pub fn filter_coords(self: &mut Frame, indeces: &[usize]) { pub fn filter_coords(self: &mut Frame, indeces: &[usize]) {
self.coords = self.coords.iter() self.coords = self
.coords
.iter()
.map(|elem| elem.clone()) .map(|elem| elem.clone())
.enumerate() .enumerate()
.filter(|&(i, _)| indeces.contains(&i)) .filter(|&(i, _)| indeces.contains(&i))
.map(|(_, elem)| elem) .map(|(_, elem)| elem)
.collect(); .collect();
self.num_atoms = self.coords.len() as u32; self.num_atoms = self.coords.len() as u32;
} }
/// Length of the frame (number of atoms) /// Length of the frame (number of atoms)
pub fn len(self: &Frame) -> usize { pub fn len(self: &Frame) -> usize {
self.num_atoms as usize self.num_atoms as usize
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -91,12 +95,12 @@ mod tests {
frame.coords[0] = [1.0, 2.0, 3.0]; frame.coords[0] = [1.0, 2.0, 3.0];
frame.coords[1] = [4.0, 5.0, 6.0]; frame.coords[1] = [4.0, 5.0, 6.0];
frame.coords[2] = [7.0, 8.0, 9.0]; frame.coords[2] = [7.0, 8.0, 9.0];
let filter: Vec<usize> = vec![1,2]; let filter: Vec<usize> = vec![1, 2];
let mut frame_new = frame.clone(); let mut frame_new = frame.clone();
frame_new.filter_coords(&filter); frame_new.filter_coords(&filter);
assert!(frame_new.num_atoms as usize == filter.len()); assert!(frame_new.num_atoms as usize == filter.len());
assert!(frame_new.coords[0] == frame.coords[1]); assert!(frame_new.coords[0] == frame.coords[1]);
assert!(frame_new.coords[1] == frame.coords[2]); assert!(frame_new.coords[1] == frame.coords[2]);
} }
#[test] #[test]

View File

@@ -1,10 +1,9 @@
use crate::*;
use crate::c_abi::xdrfile::exdrENDOFFILE; use crate::c_abi::xdrfile::exdrENDOFFILE;
use failure::Error; use crate::*;
use std::rc::Rc; use std::rc::Rc;
impl IntoIterator for XTCTrajectory { impl IntoIterator for XTCTrajectory {
type Item = Result<Rc<Frame>, Error>; type Item = Result<Rc<Frame>>;
type IntoIter = XTCTrajectoryIterator; type IntoIter = XTCTrajectoryIterator;
fn into_iter(mut self) -> Self::IntoIter { fn into_iter(mut self) -> Self::IntoIter {
@@ -13,14 +12,14 @@ impl IntoIterator for XTCTrajectory {
XTCTrajectoryIterator { XTCTrajectoryIterator {
trajectory: self, trajectory: self,
item: Rc::new(Frame::with_capacity(num_atoms)), item: Rc::new(Frame::with_capacity(num_atoms)),
has_error: false has_error: false,
} }
} }
} }
/* /*
Iterator for trajectories. This iterator yields a Result<Frame, Error> Iterator for trajectories. This iterator yields a Result<Frame, Error>
for each frame in the trajectory file and stops with yielding None once the for each frame in the trajectory file and stops with yielding None once the
trajectory is finished. Also yields None after the first occurence of an error trajectory is finished. Also yields None after the first occurence of an error
*/ */
pub struct XTCTrajectoryIterator { pub struct XTCTrajectoryIterator {
@@ -30,20 +29,21 @@ pub struct XTCTrajectoryIterator {
} }
impl Iterator for XTCTrajectoryIterator { impl Iterator for XTCTrajectoryIterator {
type Item = Result<Rc<Frame>, Error>; type Item = Result<Rc<Frame>>;
fn next(&mut self) -> Option<Self::Item> { // Reuse old frame fn next(&mut self) -> Option<Self::Item> {
// Reuse old frame
if self.has_error { if self.has_error {
return None; return None;
} }
let item: &mut Frame = match Rc::get_mut(&mut self.item) { let item: &mut Frame = match Rc::get_mut(&mut self.item) {
Some(item) => item, Some(item) => item,
None => { // caller kept frame. Create new one None => {
// caller kept frame. Create new one
self.item = Rc::new(Frame::with_capacity(self.item.num_atoms)); self.item = Rc::new(Frame::with_capacity(self.item.num_atoms));
Rc::get_mut(&mut self.item).unwrap() Rc::get_mut(&mut self.item).unwrap()
} }
}; };
match self.trajectory.read(item) { match self.trajectory.read(item) {
Ok(()) => Some(Ok(Rc::clone(&self.item))), Ok(()) => Some(Ok(Rc::clone(&self.item))),
@@ -55,12 +55,12 @@ impl Iterator for XTCTrajectoryIterator {
Some(Err(msg)) Some(Err(msg))
} }
} }
} }
} }
} }
impl IntoIterator for TRRTrajectory { impl IntoIterator for TRRTrajectory {
type Item = Result<Rc<Frame>, Error>; type Item = Result<Rc<Frame>>;
type IntoIter = TRRTrajectoryIterator; type IntoIter = TRRTrajectoryIterator;
fn into_iter(mut self) -> Self::IntoIter { fn into_iter(mut self) -> Self::IntoIter {
@@ -69,14 +69,14 @@ impl IntoIterator for TRRTrajectory {
TRRTrajectoryIterator { TRRTrajectoryIterator {
trajectory: self, trajectory: self,
item: Rc::new(Frame::with_capacity(num_atoms)), item: Rc::new(Frame::with_capacity(num_atoms)),
has_error: false has_error: false,
} }
} }
} }
/* /*
Iterator for trajectories. This iterator yields a Result<Frame, Error> Iterator for trajectories. This iterator yields a Result<Frame, Error>
for each frame in the trajectory file and stops with yielding None once the for each frame in the trajectory file and stops with yielding None once the
trajectory is finished. Also yields None after the first occurence of an error trajectory is finished. Also yields None after the first occurence of an error
*/ */
pub struct TRRTrajectoryIterator { pub struct TRRTrajectoryIterator {
@@ -86,20 +86,21 @@ pub struct TRRTrajectoryIterator {
} }
impl Iterator for TRRTrajectoryIterator { impl Iterator for TRRTrajectoryIterator {
type Item = Result<Rc<Frame>, Error>; type Item = Result<Rc<Frame>>;
fn next(&mut self) -> Option<Self::Item> { // Reuse old frame fn next(&mut self) -> Option<Self::Item> {
// Reuse old frame
if self.has_error { if self.has_error {
return None; return None;
} }
let item: &mut Frame = match Rc::get_mut(&mut self.item) { let item: &mut Frame = match Rc::get_mut(&mut self.item) {
Some(item) => item, Some(item) => item,
None => { // caller kept frame. Create new one None => {
// caller kept frame. Create new one
self.item = Rc::new(Frame::with_capacity(self.item.num_atoms)); self.item = Rc::new(Frame::with_capacity(self.item.num_atoms));
Rc::get_mut(&mut self.item).unwrap() Rc::get_mut(&mut self.item).unwrap()
} }
}; };
match self.trajectory.read(item) { match self.trajectory.read(item) {
Ok(()) => Some(Ok(Rc::clone(&self.item))), Ok(()) => Some(Ok(Rc::clone(&self.item))),
@@ -111,7 +112,7 @@ impl Iterator for TRRTrajectoryIterator {
Some(Err(msg)) Some(Err(msg))
} }
} }
} }
} }
} }
@@ -136,4 +137,4 @@ mod tests {
assert!(frames[0].step == 1, frames[0].step); assert!(frames[0].step == 1, frames[0].step);
assert!(frames[37].step == 38); assert!(frames[37].step == 38);
} }
} }

View File

@@ -8,7 +8,7 @@
//! # Basic usage example //! # Basic usage example
//! ```rust //! ```rust
//! use xdrfile::*; //! use xdrfile::*;
//! use std::path::Path; //! use std::path::Path;
//! //!
//! let mut path = Path::new("tests/1l2y.xtc"); //! let mut path = Path::new("tests/1l2y.xtc");
//! // get a handle to the file //! // get a handle to the file
@@ -16,23 +16,23 @@
//! //!
//! // find number of atoms in the file //! // find number of atoms in the file
//! let num_atoms = trj.get_num_atoms().unwrap(); //! let num_atoms = trj.get_num_atoms().unwrap();
//! //!
//! // a frame object is used to get to read or write from a trajectory //! // a frame object is used to get to read or write from a trajectory
//! // without instantiating data arrays for every step //! // without instantiating data arrays for every step
//! let mut frame = Frame::with_capacity(num_atoms); //! let mut frame = Frame::with_capacity(num_atoms);
//! //!
//! // read the first frame of the trajectory //! // read the first frame of the trajectory
//! let result = trj.read(&mut frame); //! let result = trj.read(&mut frame);
//! match result { //! match result {
//! Ok(_) => { //! Ok(_) => {
//! assert_eq!(frame.step, 1); //! assert_eq!(frame.step, 1);
//! assert_eq!(frame.num_atoms, num_atoms); //! assert_eq!(frame.num_atoms, num_atoms);
//! //!
//! let first_atom_coords = frame.coords[0]; //! let first_atom_coords = frame.coords[0];
//! assert_eq!(first_atom_coords, [-0.8901, 0.4127, -0.055499997]); //! assert_eq!(first_atom_coords, [-0.8901, 0.4127, -0.055499997]);
//! } //! }
//! Err(msg) => { //! Err(msg) => {
//! panic!("Something went wrong: {}", msg); //! panic!("Something went wrong: {}", msg);
//! } //! }
//! } //! }
//! ``` //! ```
@@ -45,12 +45,12 @@
//! //!
//! ```rust //! ```rust
//! use xdrfile::*; //! use xdrfile::*;
//! use std::path::Path; //! use std::path::Path;
//! //!
//! let mut path = Path::new("tests/1l2y.xtc"); //! let mut path = Path::new("tests/1l2y.xtc");
//! // get a handle to the file //! // get a handle to the file
//! let trj = XTCTrajectory::open(path, FileMode::Read).unwrap(); //! let trj = XTCTrajectory::open(path, FileMode::Read).unwrap();
//! //!
//! // iterate over all frames //! // iterate over all frames
//! for (idx, frame) in trj.into_iter().filter_map(Result::ok).enumerate() { //! for (idx, frame) in trj.into_iter().filter_map(Result::ok).enumerate() {
//! println!("{}", frame.time); //! println!("{}", frame.time);
@@ -58,33 +58,80 @@
//! } //! }
//! ``` //! ```
#[cfg(test)] #[cfg(test)]
#[macro_use] extern crate assert_approx_eq; #[macro_use]
extern crate assert_approx_eq;
extern crate lazy_init; extern crate lazy_init;
pub mod c_abi;
mod frame; mod frame;
mod iterator; mod iterator;
pub mod c_abi;
pub use frame::Frame; pub use frame::Frame;
pub use iterator::*; pub use iterator::*;
use c_abi::xdr_seek;
use c_abi::xdrfile; use c_abi::xdrfile;
use c_abi::xdrfile::XDRFILE; use c_abi::xdrfile::XDRFILE;
use c_abi::xdr_seek;
use c_abi::xdrfile_xtc;
use c_abi::xdrfile_trr; use c_abi::xdrfile_trr;
use c_abi::xdrfile_xtc;
use lazy_init::Lazy;
use std::cell::Cell;
use std::ffi::CString; use std::ffi::CString;
use std::path::Path; use std::path::Path;
use failure::{Error,err_msg};
use std::cell::Cell;
use lazy_init::Lazy;
#[derive(Debug, Clone)]
pub enum Error {
CouldNotOpenFile(std::path::PathBuf, FileMode),
CouldNotReadAtomNumber(u32),
CouldNotRead(u32),
CouldNotWrite(u32),
CouldNotFlush(u32),
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use Error::*;
match self {
CouldNotOpenFile(path, mode) => write!(
f,
"Failed to open file at {path:?} with mode {mode:?}",
path = path,
mode = mode
),
CouldNotReadAtomNumber(code) => write!(
f,
"Failed to read atom number from trajectory: C API returned error code {}",
code
),
CouldNotRead(code) => write!(
f,
"Failed to read trajectory: C API returned error code {}",
code
),
CouldNotWrite(code) => write!(
f,
"Failed to write trajectory: C API returned error code {}",
code
),
CouldNotFlush(code) => write!(
f,
"Failed to flush trajectory: C API returned error code {}",
code
),
}
}
}
impl std::error::Error for Error {}
type Result<T> = std::result::Result<T, Error>;
#[derive(Debug, Clone)]
pub enum FileMode { pub enum FileMode {
Write, Write,
Append, Append,
Read Read,
} }
impl FileMode { impl FileMode {
@@ -98,30 +145,35 @@ impl FileMode {
} }
fn path_to_cstring(path: &Path) -> CString { fn path_to_cstring(path: &Path) -> CString {
CString::new(path.to_str().unwrap()).unwrap() CString::new(path.to_str().unwrap()).unwrap()
} }
/// A safe wrapper around the c implementation of an XDRFile /// A safe wrapper around the c implementation of an XDRFile
struct XDRFile { struct XDRFile {
xdrfile: *mut XDRFILE, xdrfile: *mut XDRFILE,
#[allow(dead_code)]
filemode: FileMode, filemode: FileMode,
path: String, path: String,
} }
impl XDRFile { impl XDRFile {
pub fn open(path: &Path, filemode: FileMode) -> Result<XDRFile> {
pub fn open(path: &Path, filemode: FileMode) -> Result<XDRFile, Error> {
let path_p = path_to_cstring(path).into_raw(); let path_p = path_to_cstring(path).into_raw();
let mode_p = CString::new(filemode.value()).unwrap().into_raw(); let mode_p = CString::new(filemode.value()).unwrap().into_raw();
unsafe { unsafe {
let xdrfile = xdrfile::xdrfile_open(path_p, mode_p); let xdrfile = xdrfile::xdrfile_open(path_p, mode_p);
if ! xdrfile.is_null() { if !xdrfile.is_null() {
let path = String::from(path.to_str().unwrap()); let path = String::from(path.to_str().unwrap());
Ok(XDRFile { xdrfile, filemode, path }) Ok(XDRFile {
} else { // Something went wrong. But the C api does not tell us what xdrfile,
Err(err_msg("Failed to open trajectory file")) filemode,
path,
})
} else {
// Something went wrong. But the C api does not tell us what
Err(Error::CouldNotOpenFile(path.into(), filemode))
} }
} }
} }
@@ -133,127 +185,131 @@ impl Drop for XDRFile {
unsafe { unsafe {
xdrfile::xdrfile_close(self.xdrfile); xdrfile::xdrfile_close(self.xdrfile);
} }
} }
} }
/// The trajectory trait defines shared methods for xtc and trr trajectories /// The trajectory trait defines shared methods for xtc and trr trajectories
pub trait Trajectory { pub trait Trajectory {
/// Read the next step of the trajectory into the frame object /// Read the next step of the trajectory into the frame object
fn read(&mut self, frame: &mut Frame) -> Result<(), Error>; fn read(&mut self, frame: &mut Frame) -> Result<()>;
/// Write the frame to the trajectory file /// Write the frame to the trajectory file
fn write(&mut self, frame: &Frame) -> Result<(), Error>; fn write(&mut self, frame: &Frame) -> Result<()>;
/// Flush the trajectory file /// Flush the trajectory file
fn flush(&mut self) -> Result<(), Error>; fn flush(&mut self) -> Result<()>;
/// Get the number of atoms from the give trajectory /// Get the number of atoms from the give trajectory
fn get_num_atoms(&mut self) -> Result<u32, Error>; fn get_num_atoms(&mut self) -> Result<u32>;
} }
/// Read/Write XTC Trajectories /// Read/Write XTC Trajectories
pub struct XTCTrajectory { pub struct XTCTrajectory {
handle: XDRFile, handle: XDRFile,
precision: Cell<f32>, // internal mutability required for read method precision: Cell<f32>, // internal mutability required for read method
num_atoms: Lazy<Result<u32, Error>> num_atoms: Lazy<Result<u32>>,
} }
impl XTCTrajectory { impl XTCTrajectory {
pub fn open(path: &Path, filemode: FileMode) -> Result<XTCTrajectory, Error> { pub fn open(path: &Path, filemode: FileMode) -> Result<XTCTrajectory> {
let xdr = XDRFile::open(path, filemode)?; let xdr = XDRFile::open(path, filemode)?;
Ok(XTCTrajectory { handle: xdr, precision: Cell::new(1000.0), num_atoms: Lazy::new() }) Ok(XTCTrajectory {
handle: xdr,
precision: Cell::new(1000.0),
num_atoms: Lazy::new(),
})
} }
} }
impl Trajectory for XTCTrajectory { impl Trajectory for XTCTrajectory {
fn read(&mut self, frame: &mut Frame) -> Result<()> {
fn read(&mut self, frame: &mut Frame) -> Result<(), Error> {
unsafe { unsafe {
// C lib requires an i32 to be passed, but step is exposed it as u32 // C lib requires an i32 to be passed, but step is exposed it as u32
// (A step cannot be negative, can it?). So we need to create a step // (A step cannot be negative, can it?). So we need to create a step
// variable to pass to read_xtc and cast it afterwards to u32 // variable to pass to read_xtc and cast it afterwards to u32
let mut step: i32 = 0; let mut step: i32 = 0;
let code = xdrfile_xtc::read_xtc(self.handle.xdrfile, let code = xdrfile_xtc::read_xtc(
self.handle.xdrfile,
frame.num_atoms as i32, frame.num_atoms as i32,
&mut step, &mut step,
&mut frame.time, &mut frame.time,
&mut frame.box_vector, &mut frame.box_vector,
frame.coords.as_ptr() as *mut [f32; 3], frame.coords.as_ptr() as *mut [f32; 3],
&mut self.precision.get(), &mut self.precision.get(),
) as u32; ) as u32;
frame.step = step as u32; frame.step = step as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to read trajectory. Error code: {}", code))), _ => Err(Error::CouldNotRead(code)),
} }
} }
} }
fn write(&mut self, frame: &Frame) -> Result<(), Error> { fn write(&mut self, frame: &Frame) -> Result<()> {
unsafe { unsafe {
let code = xdrfile_xtc::write_xtc(self.handle.xdrfile, let code = xdrfile_xtc::write_xtc(
self.handle.xdrfile,
frame.num_atoms as i32, frame.num_atoms as i32,
frame.step as i32, frame.step as i32,
frame.time, frame.time,
frame.box_vector.as_ptr() as *mut [[f32; 3]; 3], frame.box_vector.as_ptr() as *mut [[f32; 3]; 3],
frame.coords[..].as_ptr() as *mut [f32; 3], frame.coords[..].as_ptr() as *mut [f32; 3],
1000.0) as u32; 1000.0,
) as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to write trajectory. Error code: {}", code))) _ => Err(Error::CouldNotWrite(code)),
} }
} }
} }
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<()> {
unsafe { unsafe {
let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32; let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to flush trajectory. Error code: {}", code))) _ => Err(Error::CouldNotFlush(code)),
} }
}
}
fn get_num_atoms(&mut self) -> Result<u32, Error> {
let result = self.num_atoms.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code = xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code)))
}
}
});
match result {
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
} }
} }
}
fn get_num_atoms(&mut self) -> Result<u32> {
self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code =
xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(Error::CouldNotReadAtomNumber(code)),
}
}
})
.clone()
}
}
/// Read/Write TRR Trajectories /// Read/Write TRR Trajectories
pub struct TRRTrajectory { pub struct TRRTrajectory {
handle: XDRFile, handle: XDRFile,
num_atoms: Lazy<Result<u32, Error>> num_atoms: Lazy<Result<u32>>,
} }
impl TRRTrajectory { impl TRRTrajectory {
pub fn open(path: &Path, filemode: FileMode) -> Result<TRRTrajectory, Error> { pub fn open(path: &Path, filemode: FileMode) -> Result<TRRTrajectory> {
let xdr = XDRFile::open(path, filemode)?; let xdr = XDRFile::open(path, filemode)?;
Ok(TRRTrajectory { handle: xdr, num_atoms: Lazy::new() }) Ok(TRRTrajectory {
handle: xdr,
num_atoms: Lazy::new(),
})
} }
} }
impl Trajectory for TRRTrajectory { impl Trajectory for TRRTrajectory {
fn read(&mut self, frame: &mut Frame) -> Result<()> {
fn read(&mut self, frame: &mut Frame) -> Result<(), Error> {
unsafe { unsafe {
// C lib requires an i32 to be passed, but step is exposed it as u32 // C lib requires an i32 to be passed, but step is exposed it as u32
// (A step cannot be negative, can it?). So we need to create a step // (A step cannot be negative, can it?). So we need to create a step
@@ -261,7 +317,8 @@ impl Trajectory for TRRTrajectory {
// Similar for lambda. // Similar for lambda.
let mut step: i32 = 0; let mut step: i32 = 0;
let mut lambda: f32 = 0.0; let mut lambda: f32 = 0.0;
let code = xdrfile_trr::read_trr(self.handle.xdrfile, let code = xdrfile_trr::read_trr(
self.handle.xdrfile,
frame.num_atoms as i32, frame.num_atoms as i32,
&mut step, &mut step,
&mut frame.time, &mut frame.time,
@@ -269,19 +326,20 @@ impl Trajectory for TRRTrajectory {
&mut frame.box_vector, &mut frame.box_vector,
frame.coords.as_ptr() as *mut [f32; 3], frame.coords.as_ptr() as *mut [f32; 3],
std::ptr::null_mut(), std::ptr::null_mut(),
std::ptr::null_mut() std::ptr::null_mut(),
) as u32; ) as u32;
frame.step = step as u32; frame.step = step as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to read trajectory. Error code: {}", code))) _ => Err(Error::CouldNotRead(code)),
} }
} }
} }
fn write(&mut self, frame: &Frame) -> Result<(), Error> { fn write(&mut self, frame: &Frame) -> Result<()> {
unsafe { unsafe {
let code = xdrfile_trr::write_trr(self.handle.xdrfile, let code = xdrfile_trr::write_trr(
self.handle.xdrfile,
frame.num_atoms as i32, frame.num_atoms as i32,
frame.step as i32, frame.step as i32,
frame.time, frame.time,
@@ -289,51 +347,49 @@ impl Trajectory for TRRTrajectory {
frame.box_vector.as_ptr() as *mut [[f32; 3]; 3], frame.box_vector.as_ptr() as *mut [[f32; 3]; 3],
frame.coords[..].as_ptr() as *mut [f32; 3], frame.coords[..].as_ptr() as *mut [f32; 3],
std::ptr::null_mut(), std::ptr::null_mut(),
std::ptr::null_mut()) as u32; std::ptr::null_mut(),
) as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to write trajectory. Error code: {}", code))) _ => Err(Error::CouldNotWrite(code)),
} }
} }
} }
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<()> {
unsafe { unsafe {
let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32; let code = xdr_seek::xdr_flush(self.handle.xdrfile) as u32;
match code { match code {
xdrfile::exdrOK => Ok(()), xdrfile::exdrOK => Ok(()),
_ => Err(err_msg(format!("Failed to flush trajectory. Error code: {}", code))) _ => Err(Error::CouldNotFlush(code)),
} }
}
}
fn get_num_atoms(&mut self) -> Result<u32, Error> {
let result = self.num_atoms.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code = xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code)))
}
}
});
match result {
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
} }
} }
}
fn get_num_atoms(&mut self) -> Result<u32> {
self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0;
unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw();
let code =
xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code {
xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(Error::CouldNotReadAtomNumber(code)),
}
}
})
.clone()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use tempfile::NamedTempFile; use tempfile::NamedTempFile;
#[test] #[test]
fn test_read_write_xtc() { fn test_read_write_xtc() {
@@ -413,4 +469,3 @@ mod tests {
assert_eq!(new_frame.coords, frame.coords); assert_eq!(new_frame.coords, frame.coords);
} }
} }

View File

@@ -1,9 +1,9 @@
#[cfg(test)] #[cfg(test)]
mod integration { mod integration {
use std::path::Path;
use std::rc::Rc; use std::rc::Rc;
use xdrfile::*; use xdrfile::*;
use std::path::Path;
#[test] #[test]
fn test_use_library() { fn test_use_library() {
@@ -25,8 +25,7 @@ mod integration {
let trj = XTCTrajectory::open(path, FileMode::Read).unwrap(); let trj = XTCTrajectory::open(path, FileMode::Read).unwrap();
let frames: Vec<Rc<Frame>> = trj.into_iter().filter_map(Result::ok).collect(); let frames: Vec<Rc<Frame>> = trj.into_iter().filter_map(Result::ok).collect();
for (idx, frame) in frames.iter().enumerate() { for (idx, frame) in frames.iter().enumerate() {
assert_eq!(frame.step as usize, idx+1); assert_eq!(frame.step as usize, idx + 1);
} }
} }
}
}