use serde::{Deserialize, Serialize};
use std::fmt;
use std::str::FromStr;
use crate::errors::{Error, ErrorKind, TaxonomyResult};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[non_exhaustive]
pub enum TaxRank {
Domain,
AcellularRoot,
CellularRoot,
Subdomain,
Realm,
Subrealm,
Hyperkingdom,
Superkingdom,
Kingdom,
Subkingdom,
Infrakingdom,
Parvkingdom,
Superphylum,
Phylum,
Subphylum,
Infraphylum,
Microphylum,
Superclass,
Class,
Subclass,
Infraclass,
Parvclass,
Superdivision,
Division,
Subdivision,
Infradivision,
Superlegion,
Legion,
Sublegion,
Infralegion,
Supercohort,
Cohort,
Subcohort,
Infracohort,
Superorder,
Gigaorder,
Magnorder,
Grandorder,
Mirorder,
SeriesFish,
Order,
Nanorder,
Hypoorder,
Minorder,
Suborder,
Infraorder,
Parvorder,
Section,
Subsection,
Gigafamily,
Megafamily,
Grandfamily,
Hyperfamily,
Superfamily,
Epifamily,
SeriesLepidoptera,
GroupLepidoptera,
Family,
Subfamily,
Infrafamily,
Supertribe,
Tribe,
Subtribe,
Infratribe,
Genus,
Subgenus,
Series,
SubseriesBotany,
SpeciesGroup,
SpeciesSubgroup,
Species,
Subspecies,
Varietas,
Subvarietas,
Forma,
Subforma,
Cultivar,
Breed,
Strain,
Individual,
Clade,
SeroGroup,
Biotype,
FormaSpecialis,
Isolate,
Serotype,
Genotype,
Morph,
Pathogroup,
Unspecified,
}
impl TaxRank {
pub fn to_ncbi_rank(self) -> &'static str {
match self {
TaxRank::Superkingdom => "superkingdom",
TaxRank::AcellularRoot => "acellular root",
TaxRank::CellularRoot => "cellular root",
TaxRank::Kingdom => "kingdom",
TaxRank::Subkingdom => "subkingdom",
TaxRank::Superphylum => "superphylum",
TaxRank::Phylum => "phylum",
TaxRank::Subphylum => "subphylum",
TaxRank::Superclass => "superclass",
TaxRank::Class => "class",
TaxRank::Subclass => "subclass",
TaxRank::Infraclass => "infraclass",
TaxRank::Cohort => "cohort",
TaxRank::Subcohort => "subcohort",
TaxRank::Superorder => "superorder",
TaxRank::Order => "order",
TaxRank::Suborder => "suborder",
TaxRank::Infraorder => "infraorder",
TaxRank::Parvorder => "parvorder",
TaxRank::Superfamily => "superfamily",
TaxRank::Family => "family",
TaxRank::Subfamily => "subfamily",
TaxRank::Tribe => "tribe",
TaxRank::Subtribe => "subtribe",
TaxRank::Genus => "genus",
TaxRank::Series => "series",
TaxRank::Subgenus => "subgenus",
TaxRank::SpeciesGroup => "species group",
TaxRank::SpeciesSubgroup => "species subgroup",
TaxRank::Species => "species",
TaxRank::Subspecies => "subspecies",
TaxRank::Strain => "strain",
TaxRank::Varietas => "varietas",
TaxRank::Forma => "forma",
TaxRank::Unspecified => "no rank",
TaxRank::Clade => "clade",
TaxRank::SeroGroup => "serogroup",
TaxRank::Biotype => "biotype",
TaxRank::FormaSpecialis => "forma specialis",
TaxRank::Isolate => "isolate",
TaxRank::Serotype => "serotype",
TaxRank::Genotype => "genotype",
TaxRank::Morph => "morph",
TaxRank::Pathogroup => "pathogroup",
_ => "no rank",
}
}
}
impl FromStr for TaxRank {
type Err = Error;
fn from_str(s: &str) -> TaxonomyResult<Self> {
match s.trim().to_lowercase().as_ref() {
"domain" | "regio" => Ok(TaxRank::Domain),
"subdomain" => Ok(TaxRank::Subdomain),
"realm" => Ok(TaxRank::Realm),
"acellular root" => Ok(TaxRank::AcellularRoot),
"cellular root" => Ok(TaxRank::CellularRoot),
"subrealm" => Ok(TaxRank::Subrealm),
"hyperkingdom" | "hyperregnum" => Ok(TaxRank::Hyperkingdom),
"superkingdom" | "superregnum" => Ok(TaxRank::Superkingdom),
"kingdom" | "regnum" => Ok(TaxRank::Kingdom),
"subkingdom" | "subregnum" => Ok(TaxRank::Subkingdom),
"infrakingdom" | "infraregnum" => Ok(TaxRank::Infrakingdom),
"parvkingdom" | "parvregnum" => Ok(TaxRank::Parvkingdom),
"superphylum" | "superphyla" => Ok(TaxRank::Superphylum),
"phylum" | "phyla" => Ok(TaxRank::Phylum),
"subphylum" | "subphyla" => Ok(TaxRank::Subphylum),
"infraphylum" | "infraphyla" => Ok(TaxRank::Infraphylum),
"microphylum" | "microphyla" => Ok(TaxRank::Microphylum),
"superclass" => Ok(TaxRank::Superclass),
"class" | "classis" => Ok(TaxRank::Class),
"subclass" | "subclassis" => Ok(TaxRank::Subclass),
"infraclass" => Ok(TaxRank::Infraclass),
"parvclass" => Ok(TaxRank::Parvclass),
"superlegion" => Ok(TaxRank::Superlegion),
"legion" => Ok(TaxRank::Legion),
"sublegion" => Ok(TaxRank::Sublegion),
"infralegion" => Ok(TaxRank::Infralegion),
"supercohort" => Ok(TaxRank::Supercohort),
"cohort" => Ok(TaxRank::Cohort),
"subcohort" => Ok(TaxRank::Subcohort),
"infracohort" => Ok(TaxRank::Infracohort),
"superorder" => Ok(TaxRank::Superorder),
"gigaorder" => Ok(TaxRank::Gigaorder),
"magnorder" => Ok(TaxRank::Magnorder),
"grandorder" => Ok(TaxRank::Grandorder),
"mirorder" => Ok(TaxRank::Mirorder),
"order" | "ordo" => Ok(TaxRank::Order),
"nanorder" => Ok(TaxRank::Nanorder),
"hypoorder" => Ok(TaxRank::Hypoorder),
"minorder" => Ok(TaxRank::Minorder),
"suborder" | "subordo" => Ok(TaxRank::Suborder),
"infraorder" => Ok(TaxRank::Infraorder),
"parvorder" => Ok(TaxRank::Parvorder),
"section" | "sectio" => Ok(TaxRank::Section),
"subsection" => Ok(TaxRank::Subsection),
"gigafamily" => Ok(TaxRank::Gigafamily),
"megafamily" => Ok(TaxRank::Megafamily),
"grandfamily" => Ok(TaxRank::Grandfamily),
"hyperfamily" => Ok(TaxRank::Hyperfamily),
"superfamily" => Ok(TaxRank::Superfamily),
"epifamily" => Ok(TaxRank::Epifamily),
"family" | "familia" => Ok(TaxRank::Family),
"subfamily" => Ok(TaxRank::Subfamily),
"infrafamily" => Ok(TaxRank::Infrafamily),
"supertribe" => Ok(TaxRank::Supertribe),
"tribe" | "subtribus" => Ok(TaxRank::Tribe),
"subtribe" => Ok(TaxRank::Subtribe),
"infratribe" => Ok(TaxRank::Infratribe),
"genus" | "genera" => Ok(TaxRank::Genus),
"subgenus" => Ok(TaxRank::Subgenus),
"series" => Ok(TaxRank::Series),
"species group" => Ok(TaxRank::SpeciesGroup),
"species subgroup" => Ok(TaxRank::SpeciesSubgroup),
"species" => Ok(TaxRank::Species),
"subspecies" => Ok(TaxRank::Subspecies),
"variety" | "varietas" => Ok(TaxRank::Varietas),
"subvariety" | "subvarietas" => Ok(TaxRank::Subvarietas),
"form" | "forma" => Ok(TaxRank::Forma),
"subform" | "subforma" => Ok(TaxRank::Subforma),
"cultivar" => Ok(TaxRank::Cultivar),
"breed" => Ok(TaxRank::Breed),
"strain" => Ok(TaxRank::Strain),
"serogroup" => Ok(TaxRank::SeroGroup),
"no rank" | "no_rank" => Ok(TaxRank::Unspecified),
"biotype" => Ok(TaxRank::Biotype),
"clade" => Ok(TaxRank::Clade),
"forma specialis" => Ok(TaxRank::FormaSpecialis),
"isolate" => Ok(TaxRank::Isolate),
"serotype" => Ok(TaxRank::Serotype),
"genotype" => Ok(TaxRank::Genotype),
"morph" => Ok(TaxRank::Morph),
"pathogroup" => Ok(TaxRank::Pathogroup),
_ => Err(Error::new(ErrorKind::UnknownRank(s.to_string()))),
}
}
}
impl fmt::Display for TaxRank {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let rank_str = match self {
TaxRank::Domain => "domain",
TaxRank::AcellularRoot => "acellular root",
TaxRank::CellularRoot => "cellular root",
TaxRank::Subdomain => "subdomain",
TaxRank::Realm => "realm",
TaxRank::Subrealm => "subrealm",
TaxRank::Hyperkingdom => "hyperkingdom",
TaxRank::Superkingdom => "superkingdom",
TaxRank::Kingdom => "kingdom",
TaxRank::Subkingdom => "subkingdom",
TaxRank::Infrakingdom => "infrakingdom",
TaxRank::Parvkingdom => "parvkingdom",
TaxRank::Superphylum => "superphylum",
TaxRank::Phylum => "phylum",
TaxRank::Subphylum => "subphylum",
TaxRank::Infraphylum => "infraphylum",
TaxRank::Microphylum => "microphylum",
TaxRank::Superclass => "superclass",
TaxRank::Class => "class",
TaxRank::Subclass => "subclass",
TaxRank::Infraclass => "infraclass",
TaxRank::Parvclass => "parvclass",
TaxRank::Superdivision => "superdivision",
TaxRank::Division => "division",
TaxRank::Subdivision => "subdivision",
TaxRank::Infradivision => "infradivision",
TaxRank::Superlegion => "superlegion",
TaxRank::Legion => "legion",
TaxRank::Sublegion => "sublegion",
TaxRank::Infralegion => "infralegion",
TaxRank::Supercohort => "supercohort",
TaxRank::Cohort => "cohort",
TaxRank::Subcohort => "subcohort",
TaxRank::Infracohort => "infracohort",
TaxRank::Superorder => "superorder",
TaxRank::Gigaorder => "gigaorder",
TaxRank::Magnorder => "magnorder",
TaxRank::Grandorder => "grandorder",
TaxRank::Mirorder => "mirorder",
TaxRank::SeriesFish => "series fish",
TaxRank::Order => "order",
TaxRank::Nanorder => "nanorder",
TaxRank::Hypoorder => "hypoorder",
TaxRank::Minorder => "minorder",
TaxRank::Suborder => "suborder",
TaxRank::Infraorder => "infraorder",
TaxRank::Parvorder => "parvorder",
TaxRank::Section => "section",
TaxRank::Subsection => "subsection",
TaxRank::Gigafamily => "gigafamily",
TaxRank::Megafamily => "megafamily",
TaxRank::Grandfamily => "grandfamily",
TaxRank::Hyperfamily => "hyperfamily",
TaxRank::Superfamily => "superfamily",
TaxRank::Epifamily => "epifamily",
TaxRank::SeriesLepidoptera => "series lepidoptera",
TaxRank::GroupLepidoptera => "group lepidoptera",
TaxRank::Family => "family",
TaxRank::Subfamily => "subfamily",
TaxRank::Infrafamily => "infrafamily",
TaxRank::Supertribe => "supertribe",
TaxRank::Tribe => "tribe",
TaxRank::Subtribe => "subtribe",
TaxRank::Infratribe => "infratribe",
TaxRank::Genus => "genus",
TaxRank::Subgenus => "subgenus",
TaxRank::Series => "series",
TaxRank::SubseriesBotany => "subseries botany",
TaxRank::SpeciesGroup => "species group",
TaxRank::SpeciesSubgroup => "species subgroup",
TaxRank::Species => "species",
TaxRank::Subspecies => "subspecies",
TaxRank::Varietas => "varietas",
TaxRank::Subvarietas => "subvarietas",
TaxRank::Forma => "forma",
TaxRank::Subforma => "subforma",
TaxRank::Cultivar => "cultivar",
TaxRank::Breed => "breed",
TaxRank::Strain => "strain",
TaxRank::Individual => "individual",
TaxRank::SeroGroup => "serogroup",
TaxRank::Unspecified => "no rank",
TaxRank::Biotype => "biotype",
TaxRank::Clade => "clade",
TaxRank::FormaSpecialis => "forma specialis",
TaxRank::Isolate => "isolate",
TaxRank::Serotype => "serotype",
TaxRank::Genotype => "genotype",
TaxRank::Morph => "morph",
TaxRank::Pathogroup => "pathogroup",
};
write!(f, "{}", rank_str)
}
}
#[cfg(test)]
mod test {
use super::TaxRank;
use super::TaxRank::*;
use std::str::FromStr;
static RANKS: &[super::TaxRank] = &[
Domain,
AcellularRoot,
Subdomain,
Realm,
Subrealm,
Hyperkingdom,
Superkingdom,
Kingdom,
Subkingdom,
Infrakingdom,
Parvkingdom,
Superphylum,
Phylum,
Subphylum,
Infraphylum,
Microphylum,
Superclass,
Class,
Subclass,
Infraclass,
Parvclass,
Superdivision,
Division,
Subdivision,
Infradivision,
Superlegion,
Legion,
Sublegion,
Infralegion,
Supercohort,
Cohort,
Subcohort,
Infracohort,
Superorder,
Gigaorder,
Magnorder,
Grandorder,
Mirorder,
SeriesFish,
Order,
Nanorder,
Hypoorder,
Minorder,
Suborder,
Infraorder,
Parvorder,
Section,
Subsection,
Gigafamily,
Megafamily,
Grandfamily,
Hyperfamily,
Superfamily,
Epifamily,
SeriesLepidoptera,
GroupLepidoptera,
Family,
Subfamily,
Infrafamily,
Supertribe,
Tribe,
Subtribe,
Infratribe,
Genus,
Subgenus,
Series,
SubseriesBotany,
SpeciesGroup,
SpeciesSubgroup,
Species,
Subspecies,
Varietas,
Subvarietas,
Forma,
Subforma,
Cultivar,
Breed,
Strain,
Individual,
Unspecified,
];
#[test]
fn test_ranks() {
for rank in RANKS.iter() {
let _ = rank.to_ncbi_rank();
}
}
#[test]
fn test_str_to_rank() {
for rank in RANKS.iter() {
assert!(TaxRank::from_str(rank.to_ncbi_rank()).is_ok());
}
assert!(TaxRank::from_str("fake_data").is_err());
}
#[test]
fn test_rank_to_str() {
for rank in RANKS.iter() {
let rank_str = rank.to_string();
assert!(!rank_str.is_empty());
let ncbi_str = rank.to_ncbi_rank();
if ncbi_str != "no rank" {
assert_eq!(ncbi_str, rank_str);
}
}
}
}