1use std::{
2 ffi::OsStr,
3 fs::File,
4 io::{self, BufReader, Read},
5 path::Path,
6 vec,
7};
8
9pub mod cif;
10pub mod mol;
11pub mod mol2;
12pub mod pdb;
13pub mod xyz;
14
15pub fn from_file(filename: impl AsRef<Path>) -> io::Result<(Vec<Atom>, Vec<Bond>)> {
25 let file = File::open(&filename)?;
26 let reader = BufReader::new(file);
27
28 match filename.as_ref().extension().and_then(OsStr::to_str) {
29 Some("cif") => parse(reader, FileType::CIF),
30 Some("mol") => parse(reader, FileType::MOL),
31 Some("mol2") => parse(reader, FileType::MOL2),
32 Some("pdb") => parse(reader, FileType::PDB),
33 Some("xyz") => parse(reader, FileType::XYZ),
34 _ => Err(io::Error::new(
35 io::ErrorKind::InvalidInput,
36 "Unsupported file extension",
37 )),
38 }
39}
40
41pub enum FileType {
43 CIF,
44 MOL,
45 MOL2,
46 PDB,
47 XYZ,
48}
49
50pub fn parse<P: Read>(reader: BufReader<P>, type_: FileType) -> io::Result<(Vec<Atom>, Vec<Bond>)> {
66 match type_ {
67 FileType::CIF => cif::parse(reader),
68 FileType::MOL => mol::parse(reader),
69 FileType::MOL2 => mol2::parse(reader),
70 FileType::PDB => Ok((pdb::parse(reader)?, vec![])),
71 FileType::XYZ => Ok((xyz::parse(reader)?, vec![])),
72 }
73}
74
75pub(crate) fn normalize_symbol(symbol: &str) -> String {
76 let normalized_symbol = if let Some(first_char) = symbol.chars().next() {
77 first_char.to_uppercase().collect::<String>() + &symbol[1..].to_lowercase()
78 } else {
79 String::new()
80 };
81 normalized_symbol
82}
83
84#[derive(Debug)]
85pub struct Atom {
86 pub id: usize,
87 pub atomic_number: u8,
88 pub is_disordered: bool,
89 pub coord: [f32; 3],
90}
91
92impl Atom {
93 pub fn new(id: usize, atomic_number: u8, x: f32, y: f32, z: f32) -> Self {
94 Atom {
95 id,
96 is_disordered: false,
97 atomic_number,
98 coord: [x, y, z],
99 }
100 }
101}
102
103static ATOMIC_SYMBOLS: [&str; 118] = [
104 "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl",
105 "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As",
106 "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In",
107 "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb",
108 "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl",
109 "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk",
110 "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Nh",
111 "Fl", "Mc", "Lv", "Ts", "Og",
112];
113
114#[derive(Debug)]
115pub struct Bond {
116 pub atom1: usize,
117 pub atom2: usize,
118 pub order: u8,
119 pub is_aromatic: bool,
120}
121
122impl Bond {
123 pub fn new(atom1: Atom, atom2: Atom, order: u8, is_aromatic: bool) -> Self {
124 Bond {
125 atom1: atom1.id,
126 atom2: atom2.id,
127 order,
128 is_aromatic,
129 }
130 }
131}