use crate::bcif;
use crate::error::MmCifError;
use crate::model::Structure;
use crate::parser;
use std::fs::File;
use std::io::BufReader;
#[cfg(feature = "gzip")]
use std::io::Read;
use std::path::Path;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum StructureFormat {
Mmcif,
Bcif,
}
pub fn read_structure<P: AsRef<Path>>(path: P) -> Result<Structure, MmCifError> {
let path = path.as_ref();
match detect_format(path) {
Some(format) => read_structure_with_format(path, format),
None => {
if let Ok(text) = read_mmcif_structure(path) {
return Ok(text);
}
read_bcif_structure(path)
}
}
}
pub fn read_structure_with_format<P: AsRef<Path>>(
path: P,
format: StructureFormat,
) -> Result<Structure, MmCifError> {
match format {
StructureFormat::Mmcif => read_mmcif_structure(path),
StructureFormat::Bcif => read_bcif_structure(path),
}
}
pub fn read_mmcif_structure<P: AsRef<Path>>(path: P) -> Result<Structure, MmCifError> {
let path = path.as_ref();
if is_gzipped(path) {
#[cfg(feature = "gzip")]
{
let file = File::open(path)?;
let decoder = flate2::read::GzDecoder::new(file);
let reader = BufReader::with_capacity(parser::READ_BUFFER_CAPACITY, decoder);
return parser::parse_structure(reader);
}
#[cfg(not(feature = "gzip"))]
{
return Err(MmCifError::UnsupportedFormat(
"gzip support not enabled (build with feature `gzip`)".to_string(),
));
}
}
let file = File::open(path)?;
let reader = BufReader::with_capacity(parser::READ_BUFFER_CAPACITY, file);
parser::parse_structure(reader)
}
pub fn read_bcif_structure<P: AsRef<Path>>(path: P) -> Result<Structure, MmCifError> {
let path = path.as_ref();
if is_gzipped(path) {
#[cfg(feature = "gzip")]
{
let file = File::open(path)?;
let mut decoder = flate2::read::GzDecoder::new(file);
let mut bytes = Vec::new();
decoder.read_to_end(&mut bytes)?;
return bcif::read_bcif_bytes(&bytes);
}
#[cfg(not(feature = "gzip"))]
{
return Err(MmCifError::UnsupportedFormat(
"gzip support not enabled (build with feature `gzip`)".to_string(),
));
}
}
bcif::read_bcif_structure(path)
}
fn is_gzipped(path: &Path) -> bool {
path.extension()
.map(|e| e.eq_ignore_ascii_case("gz"))
.unwrap_or(false)
}
fn detect_format(path: &Path) -> Option<StructureFormat> {
let probe = if is_gzipped(path) {
path.file_stem().map(Path::new).map(|p| p.to_path_buf())
} else {
None
};
let target = probe.as_deref().unwrap_or(path);
let ext = target.extension()?.to_string_lossy().to_ascii_lowercase();
match ext.as_str() {
"cif" | "mmcif" => Some(StructureFormat::Mmcif),
"bcif" => Some(StructureFormat::Bcif),
_ => None,
}
}