use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum StereoMode {
#[default]
Standard,
Ignore,
Relative,
Racemic,
UseChiralFlag,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Options {
add_hydrogens: bool,
aux_info: bool,
stereo: StereoMode,
fixed_h: bool,
reconnect_metals: bool,
keto_enol: bool,
tautomer_15: bool,
chiral_flag: Option<bool>,
timeout: Option<Duration>,
save_opt: bool,
polymers: Polymers,
no_frame_shift: bool,
fold_sru: bool,
no_edits: bool,
allow_pseudo_atoms: bool,
extra: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
#[non_exhaustive]
pub enum Polymers {
#[default]
Off,
On,
Legacy,
}
impl Default for Options {
fn default() -> Self {
Self::new()
}
}
impl From<()> for Options {
fn from((): ()) -> Self {
Options::new()
}
}
impl From<&Options> for Options {
fn from(options: &Options) -> Self {
options.clone()
}
}
impl Options {
#[must_use]
pub fn new() -> Self {
Options {
add_hydrogens: true,
aux_info: true,
stereo: StereoMode::Standard,
fixed_h: false,
reconnect_metals: false,
keto_enol: false,
tautomer_15: false,
chiral_flag: None,
timeout: None,
save_opt: false,
polymers: Polymers::Off,
no_frame_shift: false,
fold_sru: false,
no_edits: false,
allow_pseudo_atoms: false,
extra: Vec::new(),
}
}
#[must_use]
pub fn add_hydrogens(mut self, yes: bool) -> Self {
self.add_hydrogens = yes;
self
}
#[must_use]
pub fn aux_info(mut self, yes: bool) -> Self {
self.aux_info = yes;
self
}
#[must_use]
pub fn stereo(mut self, mode: StereoMode) -> Self {
self.stereo = mode;
self
}
#[must_use]
pub fn fixed_h(mut self, yes: bool) -> Self {
self.fixed_h = yes;
self
}
#[must_use]
pub fn reconnect_metals(mut self, yes: bool) -> Self {
self.reconnect_metals = yes;
self
}
#[must_use]
pub fn keto_enol_tautomerism(mut self, yes: bool) -> Self {
self.keto_enol = yes;
self
}
#[must_use]
pub fn tautomerism_15(mut self, yes: bool) -> Self {
self.tautomer_15 = yes;
self
}
#[must_use]
pub fn chiral_flag(mut self, flag: Option<bool>) -> Self {
self.chiral_flag = flag;
self
}
#[must_use]
pub fn timeout(mut self, dur: Duration) -> Self {
self.timeout = Some(dur);
self
}
#[must_use]
pub fn save_opt(mut self, yes: bool) -> Self {
self.save_opt = yes;
self
}
#[must_use]
pub fn polymers(mut self, mode: Polymers) -> Self {
self.polymers = mode;
self
}
#[must_use]
pub fn no_frame_shift(mut self, yes: bool) -> Self {
self.no_frame_shift = yes;
self
}
#[must_use]
pub fn fold_sru(mut self, yes: bool) -> Self {
self.fold_sru = yes;
self
}
#[must_use]
pub fn no_edits(mut self, yes: bool) -> Self {
self.no_edits = yes;
self
}
#[must_use]
pub fn allow_pseudo_atoms(mut self, yes: bool) -> Self {
self.allow_pseudo_atoms = yes;
self
}
#[must_use]
pub fn raw(mut self, token: impl Into<String>) -> Self {
self.extra.push(token.into());
self
}
#[must_use]
pub fn is_standard(&self) -> bool {
!self.fixed_h
&& !self.reconnect_metals
&& !self.keto_enol
&& !self.tautomer_15
&& self.chiral_flag.is_none()
&& matches!(self.stereo, StereoMode::Standard | StereoMode::Ignore)
&& matches!(self.polymers, Polymers::Off)
&& self.extra.is_empty()
}
const PREFIX: &'static str = if cfg!(windows) { "/" } else { "-" };
#[must_use]
pub fn to_arg_string(&self) -> String {
let mut tokens: Vec<String> = Vec::new();
let mut push = |t: &str| tokens.push(format!("{}{t}", Self::PREFIX));
if !self.add_hydrogens {
push("DoNotAddH");
}
if !self.aux_info {
push("AuxNone");
}
match self.stereo {
StereoMode::Standard => {}
StereoMode::Ignore => push("SNon"),
StereoMode::Relative => push("SRel"),
StereoMode::Racemic => push("SRac"),
StereoMode::UseChiralFlag => push("SUCF"),
}
if self.fixed_h {
push("FixedH");
}
if self.reconnect_metals {
push("RecMet");
}
if self.keto_enol {
push("KET");
}
if self.tautomer_15 {
push("15T");
}
match self.chiral_flag {
Some(true) => push("ChiralFlagON"),
Some(false) => push("ChiralFlagOFF"),
None => {}
}
if let Some(dur) = self.timeout {
let ms = dur.as_millis();
push(&format!("WM{ms}"));
}
if self.save_opt {
push("SaveOpt");
}
match self.polymers {
Polymers::Off => {}
Polymers::On => push("Polymers"),
Polymers::Legacy => push("Polymers105"),
}
if self.no_frame_shift {
push("NoFrameShift");
}
if self.fold_sru {
push("FoldSRU");
}
if self.no_edits {
push("NoEdits");
}
if self.allow_pseudo_atoms {
push("NPZz");
}
for token in &self.extra {
push(token);
}
tokens.join(" ")
}
}