use std::fmt;
use crate::{
LaunchType, LicenseCategory, ProcessExpense, Spec, SpecData, ToolCategory,
tool_definitions::{
Tool, abmpnn, aggrescan3d, alphafold3, antibody_annotator, antifold, bindcraft, biophi,
boltz_adme, boltz2, boltzgen, catpred, chai1, deepimmuno, deepsp, deepstabp, dlkcat,
enzymemap, esmfold2, genie3, germinal, gromacs, highfold, igblast, igdesign, immunebuilder,
ligandmpnn, mber, netsolp, opendde, orca, pdbbind, placer, proteinmpnn, proteinmpnn_ddg,
protenix, rdkit, retrobiocat, rfantibody, rfdiffusion3, tap, thermompnn, tlimmuno,
},
};
#[derive(Debug, Clone, Copy)]
pub enum Identity {
Installed(Tool),
Alias {
tool: Tool,
slug: &'static str,
name: Option<&'static str>,
},
Uninstalled {
slug: &'static str,
name: &'static str,
},
}
impl Identity {
pub const fn slug(self) -> &'static str {
match self {
Self::Installed(tool) => tool.slug(),
Self::Alias { slug, .. } | Self::Uninstalled { slug, .. } => slug,
}
}
pub const fn name(self) -> &'static str {
match self {
Self::Installed(tool) => tool.name(),
Self::Alias {
tool, name: None, ..
} => tool.name(),
Self::Alias {
name: Some(name), ..
}
| Self::Uninstalled { name, .. } => name,
}
}
pub const fn tool(self) -> Option<Tool> {
match self {
Self::Installed(tool) | Self::Alias { tool, .. } => Some(tool),
Self::Uninstalled { .. } => None,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DataType {
MmCif,
Pdb,
AaSequence,
DnaSequence,
RnaSequence,
Csv,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum DataCategory {
Structure,
Sequence,
Table,
}
impl DataCategory {
pub const fn label(self) -> &'static str {
match self {
Self::Structure => "Structure",
Self::Sequence => "Seq",
Self::Table => "CSV",
}
}
pub const fn suffixes(self) -> &'static [&'static str] {
match self {
Self::Structure => &[".cif", ".mmcif", ".pdb", ".ent"],
Self::Sequence => &[".fa", ".fasta", ".faa", ".fas"],
Self::Table => &[".csv"],
}
}
}
impl fmt::Display for DataCategory {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Structure => "Structure",
Self::Sequence => "Sequence",
Self::Table => "Table",
};
write!(f, "{s}")
}
}
impl DataType {
pub const fn category(self) -> DataCategory {
match self {
Self::MmCif | Self::Pdb => DataCategory::Structure,
Self::AaSequence | Self::DnaSequence | Self::RnaSequence => DataCategory::Sequence,
Self::Csv => DataCategory::Table,
}
}
pub const fn feeds(self, wanted: Self) -> bool {
matches!(
(self, wanted),
(Self::MmCif, Self::MmCif)
| (Self::Pdb, Self::Pdb)
| (Self::AaSequence, Self::AaSequence)
| (Self::DnaSequence, Self::DnaSequence)
| (Self::RnaSequence, Self::RnaSequence)
| (Self::Csv, Self::Csv)
)
}
pub const fn as_str(self) -> &'static str {
match self {
Self::MmCif => "MmCif",
Self::Pdb => "Pdb",
Self::AaSequence => "AaSequence",
Self::DnaSequence => "DnaSequence",
Self::RnaSequence => "RnaSequence",
Self::Csv => "Csv",
}
}
}
impl fmt::Display for DataType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Self::MmCif => "mmCIF",
Self::Pdb => "PDB",
Self::AaSequence => "Amino acid sequence",
Self::DnaSequence => "DNA sequence",
Self::RnaSequence => "RNA sequence",
Self::Csv => "CSV",
};
write!(f, "{s}")
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum InputForm {
File,
Residues,
Document(&'static str),
}
impl InputForm {
pub const fn kind(self) -> &'static str {
match self {
Self::File => "file",
Self::Residues => "residues",
Self::Document(_) => "document",
}
}
pub const fn dialect(self) -> Option<&'static str> {
match self {
Self::Document(dialect) => Some(dialect),
_ => None,
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct PrimaryInput {
pub field: &'static str,
pub accepts: &'static [DataType],
pub form: InputForm,
}
impl PrimaryInput {
pub const fn new(field: &'static str, accepts: &'static [DataType]) -> Self {
Self {
field,
accepts,
form: InputForm::File,
}
}
pub const fn residues(field: &'static str, accepts: &'static [DataType]) -> Self {
Self {
field,
accepts,
form: InputForm::Residues,
}
}
pub const fn document(
field: &'static str,
accepts: &'static [DataType],
dialect: &'static str,
) -> Self {
Self {
field,
accepts,
form: InputForm::Document(dialect),
}
}
pub fn accepts(&self, produced: DataType) -> bool {
self.accepts.iter().any(|wanted| produced.feeds(*wanted))
}
}
#[derive(Debug, Clone, Copy)]
pub struct CatalogEntry {
pub identity: Identity,
pub categories: &'static [ToolCategory],
pub launch_type: LaunchType,
pub license_type: LicenseCategory,
pub expense: ProcessExpense,
pub top_choice: bool,
pub spec: SpecData<&'static str>,
pub primary_output: Option<DataType>,
pub primary_inputs: &'static [PrimaryInput],
}
impl CatalogEntry {
pub const fn slug(&self) -> &'static str {
self.identity.slug()
}
pub const fn name(&self) -> &'static str {
self.identity.name()
}
pub fn to_spec(&self) -> Spec {
Spec {
slug: self.slug().to_owned(),
data: self.spec.to_owned_data(),
}
}
}
pub const ALL: &[&CatalogEntry] = &[
&rdkit::ENTRY,
&alphafold3::ENTRY,
&opendde::ENTRY,
&boltz2::ENTRY,
&chai1::ENTRY,
&protenix::ENTRY,
&esmfold2::ENTRY,
&immunebuilder::ENTRY,
&highfold::ENTRY,
&pdbbind::ENTRY,
&enzymemap::ENTRY,
&retrobiocat::ENTRY,
&boltzgen::ENTRY,
&bindcraft::ENTRY,
&gromacs::ENTRY,
&orca::ENTRY,
&igblast::ENTRY,
&biophi::ENTRY,
&antifold::ENTRY,
&abmpnn::ENTRY,
&proteinmpnn::ENTRY,
&ligandmpnn::ENTRY,
&proteinmpnn_ddg::ENTRY,
&rfdiffusion3::ENTRY,
&rfantibody::ENTRY,
&germinal::ENTRY,
&mber::ENTRY,
&igdesign::ENTRY,
&thermompnn::ENTRY,
&boltz_adme::ENTRY,
&genie3::ENTRY,
&deepsp::ENTRY,
&deepimmuno::ENTRY,
&tlimmuno::ENTRY,
&netsolp::ENTRY,
&deepstabp::ENTRY,
&aggrescan3d::ENTRY,
&dlkcat::ENTRY,
&catpred::ENTRY,
&antibody_annotator::ENTRY,
&tap::ENTRY,
&placer::ENTRY,
];
pub fn by_slug(slug: &str) -> Option<&'static CatalogEntry> {
ALL.iter().find(|entry| entry.slug() == slug).copied()
}