use gut::fs::*;
use gut::prelude::*;
use gchemol_core::Molecule;
pub trait FromFile: Sized {
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self>;
}
pub trait ToFile {
fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()>;
}
pub trait StringIO {
fn format_as<S: AsRef<str>>(&self, fmt: S) -> Result<String>;
fn parse_from<R: Read + Seek, S: AsRef<str>>(s: R, fmt: S) -> Result<Molecule>;
fn from_str<S: AsRef<str>>(s: &str, fmt: S) -> Result<Molecule> {
let f = std::io::Cursor::new(s.as_bytes());
Self::parse_from(f, fmt)
}
}
impl FromFile for String {
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
gut::fs::read_file(path)
}
}
impl ToFile for str {
fn to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
gut::fs::write_to_file(path, &self)
}
}
impl FromFile for Molecule {
fn from_file<P: AsRef<Path>>(path: P) -> Result<Self> {
if let Some(mol) = read(path)?.last() {
return Ok(mol);
}
bail!("No molecule found!");
}
}
impl ToFile for Molecule {
fn to_file<T: AsRef<Path>>(&self, path: T) -> Result<()> {
write(path, vec![self])
}
}
impl StringIO for Molecule {
fn format_as<S: AsRef<str>>(&self, fmt: S) -> Result<String> {
let fmt = fmt.as_ref();
crate::formats::format_as_chemical_file(&self, fmt)
}
fn parse_from<R: Read + Seek, S: AsRef<str>>(s: R, fmt: S) -> Result<Molecule> {
read_from(s, &fmt)?
.last()
.ok_or(format_err!("Parse molecule failure in format: {}", fmt.as_ref()))
}
}
mod find {
use super::*;
use walkdir::{DirEntry, WalkDir};
fn matching(pattern: &str, entry: Option<DirEntry>) -> Option<PathBuf> {
let entry = entry?;
if entry.file_type().is_file() {
let rx = regex::Regex::new(pattern).ok()?;
let s = entry.file_name().to_str()?;
if rx.find(s).is_some() {
return entry.into_path().into();
}
}
None
}
pub fn find_files<'a>(pattern: &'a str, root: &Path, recursive: bool) -> impl Iterator<Item = PathBuf> + 'a {
let mut walk = WalkDir::new(root).follow_links(false).sort_by_file_name();
if !recursive {
walk = walk.max_depth(1);
}
walk.into_iter()
.filter_map(|entry| matching(pattern, entry.ok()))
}
#[test]
fn test_find() -> Result<()> {
let root = "./tests/files";
let files = find_files(r"\.xyz$", root.as_ref(), true).collect_vec();
assert!(!files.is_empty());
for file in files {
assert!(file.to_string_lossy().ends_with(".xyz"));
}
let root = "./tests/files";
let files = find_files(r"\.cif$", root.as_ref(), false).collect_vec();
assert!(files.is_empty());
let root = "./tests/files/cif";
let files = find_files(r"\.cif$", root.as_ref(), false).collect_vec();
assert!(!files.is_empty());
for file in files {
assert!(file.to_string_lossy().ends_with(".cif"));
}
Ok(())
}
}
pub use self::find::find_files;
pub fn read<P: AsRef<Path>>(path: P) -> Result<impl Iterator<Item = Molecule>> {
let path = path.as_ref();
crate::formats::ChemicalFileParser::guess_from_path(path)
.ok_or(format_err!("No parser for path: {:?}", path))?
.parse_molecules(path.as_ref())
}
pub fn read_all<P: AsRef<Path>>(path: P) -> Result<Vec<Molecule>> {
let mols: Vec<_> = read(path)?.collect();
Ok(mols)
}
pub fn read_from<R: Read + Seek, S: AsRef<str>>(source: R, fmt: S) -> Result<impl Iterator<Item = Molecule>> {
let cf = crate::formats::ChemicalFileParser::new(fmt.as_ref());
let r = gchemol_parser::TextReader::new(source);
cf.parse_molecules_from(r)
}
pub fn guess_format_from_path(path: &Path) -> Option<String> {
crate::formats::ChemicalFileParser::guess_format_from_path(path)
}
pub fn write<'a, P: AsRef<Path>>(path: P, mols: impl IntoIterator<Item = &'a Molecule>) -> Result<()> {
crate::formats::write_chemical_file(path.as_ref(), mols, None)
}
pub fn write_format<'a, P: AsRef<Path>>(path: P, mols: impl IntoIterator<Item = &'a Molecule>, fmt: &str) -> Result<()> {
crate::formats::write_chemical_file(path.as_ref(), mols, Some(fmt))
}