use crate::errors::SelectError;
use crate::system::System;
use regex::Regex;
use std::fmt;
#[derive(Debug, Clone)]
pub enum Name {
String(String),
Regex(Regex),
}
impl Name {
pub fn new(string: &str) -> Result<Self, SelectError> {
if string.starts_with("r'") {
let regex = match Regex::new(&(string[2..string.len() - 1])) {
Ok(reg) => reg,
Err(_) => return Err(SelectError::InvalidRegex(string.to_owned())),
};
Ok(Name::Regex(regex))
} else {
Ok(Name::String(string.to_owned()))
}
}
pub fn match_groups(&self, system: &System, atom_index: usize) -> Result<bool, SelectError> {
match self {
Name::String(s) => match system.group_isin(s, atom_index) {
Err(_) => Err(SelectError::GroupNotFound(s.to_string())),
Ok(result) => Ok(result),
},
Name::Regex(r) => {
let group_names = system.get_groups().names_iter();
for name in group_names {
if r.is_match(name) {
return Ok(system.group_isin(name, atom_index).expect(
"FATAL GROAN ERROR | Name::match_groups | Regex arm: group must exist.",
));
}
}
Ok(false)
}
}
}
pub fn match_labels(&self, system: &System, atom_index: usize) -> Result<bool, SelectError> {
let labeled = system.get_labeled_atoms();
match self {
Name::String(s) => match labeled.get(s) {
Some(&x) => Ok(x == atom_index),
None => Err(SelectError::LabelNotFound(s.to_string())),
},
Name::Regex(r) => {
let label_names = labeled.keys();
for name in label_names {
if r.is_match(name) {
return Ok(*labeled.get(name).expect(
"FATAL GROAN ERROR | Name::match_labels | Regex arm: label must exist.",
) == atom_index);
}
}
Ok(false)
}
}
}
}
impl fmt::Display for Name {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Name::String(s) => write!(f, "{}", s),
Name::Regex(r) => write!(f, "{}", r),
}
}
}
impl PartialEq<Name> for Name {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Name::String(s), Name::String(t)) => s == t,
(Name::String(s), Name::Regex(t)) => s == t.as_str(),
(Name::Regex(s), Name::String(t)) => s.as_str() == t,
(Name::Regex(s), Name::Regex(t)) => s.as_str() == t.as_str(),
}
}
}
impl PartialEq<str> for Name {
fn eq(&self, other: &str) -> bool {
match self {
Name::String(s) => s == other,
Name::Regex(s) => s.is_match(other),
}
}
}
impl PartialEq<String> for Name {
fn eq(&self, other: &String) -> bool {
match self {
Name::String(s) => s == other,
Name::Regex(s) => s.is_match(other),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::select::Select;
#[test]
fn match_groups() {
let mut system = System::from_file("test_files/example.gro").unwrap();
system.read_ndx("test_files/index.ndx").unwrap();
let selection = Select::GroupName(vec![
Name::new("Membrane").unwrap(),
Name::new("r'membrane'").unwrap(),
]);
match selection {
Select::GroupName(v) => {
let membrane = &v[0];
for atom_index in 0..system.get_n_atoms() {
let result = membrane.match_groups(&system, atom_index).unwrap();
if (61..=6204).contains(&atom_index) {
assert!(result);
} else {
assert!(!result);
}
}
let regex = &v[1];
for atom_index in 0..system.get_n_atoms() {
let result = regex.match_groups(&system, atom_index).unwrap();
if atom_index < 61 {
assert!(result);
} else {
assert!(!result);
}
}
}
_ => panic!("This can't happen."),
}
}
}