6 Commits

Author SHA1 Message Date
daniel
e77f43d8ae version up 2020-11-07 11:57:48 +01:00
daniel
d16421708d test some error types 2020-11-07 11:57:07 +01:00
Daniel Bauer
337a5a5c1d Merge pull request #1 from Yoshanuikabundi/remove-failure
Remove failure
2020-11-07 11:53:07 +01:00
Josh Mitchell
cbd45f74dc Replace failure library with new Error type 2020-11-07 20:12:41 +11:00
Josh Mitchell
0a613c2022 Suppressed or corrected hints and warnings 2020-11-07 20:05:37 +11:00
Josh Mitchell
e30a175d0d Format with rustfmt 2020-11-07 20:03:05 +11:00
10 changed files with 322 additions and 194 deletions

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "xdrfile" name = "xdrfile"
version = "0.1.0" version = "0.2.0"
authors = ["Daniel Bauer <bauer@cbs.tu-darmstadt.de>"] authors = ["Daniel Bauer <bauer@cbs.tu-darmstadt.de>"]
license = "LGPL-3.0-only" license = "LGPL-3.0-only"
edition = "2018" edition = "2018"
@@ -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]
@@ -129,10 +128,15 @@ 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);

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,
@@ -89,11 +88,17 @@ mod tests {
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);
} }
@@ -111,11 +116,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_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);
} }
@@ -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,
@@ -81,9 +80,15 @@ mod tests {
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);
} }
@@ -98,9 +103,15 @@ 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);
} }

View File

@@ -26,38 +26,44 @@ impl Default for Frame {
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))
@@ -72,8 +78,6 @@ impl Frame {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
@@ -91,7 +95,7 @@ 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());

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,7 +12,7 @@ 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,
} }
} }
} }
@@ -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))),
@@ -60,7 +60,7 @@ impl Iterator for XTCTrajectoryIterator {
} }
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,7 +69,7 @@ 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,
} }
} }
} }
@@ -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))),

View File

@@ -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, PartialEq)]
pub enum FileMode { pub enum FileMode {
Write, Write,
Append, Append,
Read Read,
} }
impl FileMode { impl FileMode {
@@ -99,29 +146,34 @@ 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))
} }
} }
} }
@@ -138,43 +190,46 @@ impl Drop for 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,
@@ -185,75 +240,76 @@ impl Trajectory for XTCTrajectory {
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> { fn get_num_atoms(&mut self) -> Result<u32> {
let result = self.num_atoms.get_or_create(|| { self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0; let mut num_atoms: i32 = 0;
unsafe { unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap(); let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw(); let path_p = path.into_raw();
let code = xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32; let code =
xdrfile_xtc::read_xtc_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code { match code {
xdrfile::exdrOK => Ok(num_atoms as u32), xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code))) _ => Err(Error::CouldNotReadAtomNumber(code)),
} }
} }
}); })
match result { .clone()
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
}
} }
} }
/// 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,46 +347,44 @@ 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> { fn get_num_atoms(&mut self) -> Result<u32> {
let result = self.num_atoms.get_or_create(|| { self.num_atoms
.get_or_create(|| {
let mut num_atoms: i32 = 0; let mut num_atoms: i32 = 0;
unsafe { unsafe {
let path = CString::new(self.handle.path.as_str()).unwrap(); let path = CString::new(self.handle.path.as_str()).unwrap();
let path_p = path.into_raw(); let path_p = path.into_raw();
let code = xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32; let code =
xdrfile_trr::read_trr_natoms(path_p, &mut num_atoms as *const i32) as u32;
match code { match code {
xdrfile::exdrOK => Ok(num_atoms as u32), xdrfile::exdrOK => Ok(num_atoms as u32),
_ => Err(err_msg(format!("Failed to read atom number from trajectory. Error code: {}", code))) _ => Err(Error::CouldNotReadAtomNumber(code)),
} }
} }
}); })
match result { .clone()
Ok(val) => Ok(*val),
// ugly hack because failure::Error is not "Clone"
Err(err) => Err(err_msg(format!("{}", err)))
}
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@@ -412,5 +468,50 @@ mod tests {
assert_eq!(new_frame.box_vector, frame.box_vector); assert_eq!(new_frame.box_vector, frame.box_vector);
assert_eq!(new_frame.coords, frame.coords); assert_eq!(new_frame.coords, frame.coords);
} }
}
#[test]
fn test_err_could_not_open() {
let file_name = "non-existent.xtc";
let path = Path::new(&file_name);
if let Err(e) = XDRFile::open(path, FileMode::Read) {
match e {
Error::CouldNotOpenFile(err_path, err_mode) => {
assert_eq!(path, err_path);
assert!(FileMode::Read == err_mode)
}
_ => panic!("Wrong Error type"),
}
}
}
#[test]
fn test_err_could_not_read_atom_nr() {
let file_name = "README.md"; // not a trajectory
let path = Path::new(&file_name);
let mut trr = TRRTrajectory::open(path, FileMode::Read).unwrap();
if let Err(e) = trr.get_num_atoms() {
match e {
Error::CouldNotReadAtomNumber(code) => {
assert_eq!(xdrfile::exdrMAGIC, code);
}
_ => panic!("Wrong Error type"),
}
}
}
#[test]
fn test_err_could_not_read() {
let file_name = "README.md"; // not a trajectory
let path = Path::new(&file_name);
let mut frame = Frame::with_capacity(1);
let mut trr = TRRTrajectory::open(path, FileMode::Read).unwrap();
if let Err(e) = trr.read(&mut frame) {
match e {
Error::CouldNotRead(code) => {
assert_eq!(xdrfile::exdrMAGIC, code);
}
_ => panic!("Wrong Error type"),
}
}
}
}

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