use std::io::{BufRead, Read, Seek};
use super::*;
use crate::error::*;
use crate::structs::PDB;
use crate::StrictnessLevel;
#[cfg(feature = "compression")]
use super::mmcif::open_mmcif_bufread;
#[cfg(feature = "compression")]
use flate2::read::GzDecoder;
#[cfg(feature = "compression")]
use std::fs;
pub fn open(
filename: impl AsRef<str>,
level: StrictnessLevel,
) -> Result<(PDB, Vec<PDBError>), Vec<PDBError>> {
if check_extension(&filename, "pdb") {
open_pdb(filename, level)
} else if check_extension(&filename, "cif") {
open_mmcif(filename, level)
} else {
Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Incorrect extension",
"Could not determine the type of the given file, make it .pdb or .cif",
Context::show(filename.as_ref()),
)])
}
}
#[cfg(feature = "compression")]
pub fn open_gz(
filename: impl AsRef<str>,
level: StrictnessLevel,
) -> Result<(PDB, Vec<PDBError>), Vec<PDBError>> {
let filename = filename.as_ref();
if check_extension(filename, "gz") {
let file = fs::File::open(filename).map_err(|_| {
vec![PDBError::new(
ErrorLevel::BreakingError,
"Could not open file",
"Could not open the given file, make sure it exists and you have the correct permissions",
Context::show(filename),
)]
})?;
let decompressor = GzDecoder::new(file);
let reader = std::io::BufReader::new(decompressor);
if check_extension(&filename[..filename.len() - 3], "pdb") {
open_pdb_raw(reader, Context::show(filename), level)
} else if check_extension(&filename[..filename.len() - 3], "cif") {
open_mmcif_bufread(reader, level)
} else {
Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Incorrect extension",
"Could not determine the type of the given file, make it .pdb.gz or .cif.gz",
Context::show(filename),
)])
}
} else {
Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Incorrect extension",
"Could not determine the type of the given file, make it .pdb.gz or .cif.gz",
Context::show(filename),
)])
}
}
pub fn open_raw<T: std::io::Read + std::io::Seek>(
mut input: std::io::BufReader<T>,
level: StrictnessLevel,
) -> Result<(PDB, Vec<PDBError>), Vec<PDBError>> {
let mut first_line = String::new();
if input.read_line(&mut first_line).is_err() {
return Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Buffer could not be read",
"The buffer provided to `open_raw` could not be read.",
Context::None,
)]);
}
if input.rewind().is_err() {
return Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Buffer could not be read",
"The buffer provided to `open_raw` could not be rewound to the start.",
Context::None,
)]);
}
if first_line.starts_with("HEADER") {
open_pdb_raw(input, Context::None, level)
} else if first_line.starts_with("data_") {
let mut contents = String::new();
if input.read_to_string(&mut contents).is_ok() {
open_mmcif_raw(&contents, level)
} else {
Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Buffer could not be read",
"The buffer provided to `open_raw` could not be read to end.",
Context::show(&first_line),
)])
}
} else {
Err(vec![PDBError::new(
ErrorLevel::BreakingError,
"Could not determine file type",
"Could not determine the type of the given file, make it .pdb or .cif",
Context::show(&first_line),
)])
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn open_invalid() {
assert!(open("file.png", StrictnessLevel::Medium).is_err());
assert!(open("file.mmcif", StrictnessLevel::Medium).is_err());
assert!(open("file.pdbml", StrictnessLevel::Medium).is_err());
assert!(open("file.pd", StrictnessLevel::Medium).is_err());
}
#[test]
fn open_not_existing() {
let pdb =
open("file.pdb", StrictnessLevel::Medium).expect_err("This file should not exist.");
assert_eq!(pdb[0].short_description(), "Could not open file");
let cif =
open("file.cif", StrictnessLevel::Medium).expect_err("This file should not exist.");
assert_eq!(cif[0].short_description(), "Could not open file");
}
}