nucleobases 0.1.0

Common library for cross crate standardization of nucleobases in code
Documentation
use std::marker::Copy;
use std::clone::Clone;
use std::hash::Hash;
use std::convert::TryFrom;

use std::fmt;
use std::cmp;

#[derive(Copy, Clone, cmp::Eq, cmp::PartialEq, cmp::Ord, cmp::PartialOrd, Hash, fmt::Debug)]
pub enum Nucleobase {
    Adenine,
    Cytosine,
    Guanine,
    Thymine,
    Uracil,
}

pub fn is_purine(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Guanine => true,
        Nucleobase::Cytosine | Nucleobase::Thymine | Nucleobase::Uracil => false,
    }
}

pub fn is_pyrimidine(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Guanine => false,
        Nucleobase::Cytosine | Nucleobase::Thymine | Nucleobase::Uracil => true,
    }
}

pub fn is_ketone(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Cytosine => false,
        Nucleobase::Guanine | Nucleobase::Thymine | Nucleobase::Uracil => true,
    }
}

pub fn is_amine(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Cytosine => true,
        Nucleobase::Guanine | Nucleobase::Thymine | Nucleobase::Uracil => false,
    }
}

pub fn is_ribonucleotide_base(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Cytosine | Nucleobase::Guanine | Nucleobase::Uracil => true,
        Nucleobase::Thymine => false,
    }
}

pub fn is_deoxyribonucleotide_base(base: &Nucleobase) -> bool {
    match base {
        Nucleobase::Adenine | Nucleobase::Cytosine | Nucleobase::Guanine | Nucleobase::Thymine => true,
        Nucleobase::Uracil => false
    }
}

pub fn to_letter_code(base: &Nucleobase) -> char {
    match base {
        Nucleobase::Adenine => 'A',
        Nucleobase::Cytosine => 'C',
        Nucleobase::Guanine => 'G',
        Nucleobase::Thymine => 'T',
        Nucleobase::Uracil => 'U',
    }
}

pub fn from_letter_code(letter_code: &char) -> Option<Nucleobase> {
    match letter_code {
        'A' | 'a' => Some(Nucleobase::Adenine),
        'C' | 'c' => Some(Nucleobase::Cytosine),
        'G' | 'g' => Some(Nucleobase::Guanine),
        'T' | 't' => Some(Nucleobase::Thymine),
        'U' | 'u' => Some(Nucleobase::Uracil),
        _ => None
    }
}

impl Nucleobase {
    pub fn is_purine(&self) -> bool { is_purine(self) }

    pub fn is_pyrimidine(&self) -> bool { is_pyrimidine(self) }

    pub fn is_ketone(&self) -> bool { is_ketone(self) }

    pub fn is_amine(&self) -> bool { is_amine(self) }

    pub fn is_ribonucleotide_base(&self) -> bool { is_ribonucleotide_base(self) }

    pub fn is_deoxyribonucleotide_base(&self) -> bool { is_deoxyribonucleotide_base(self) }

    pub fn to_letter_code(&self) -> char { to_letter_code(self) }

    pub fn from_letter_code(letter_code: &char) -> Option<Self> { from_letter_code(letter_code) }
}

impl TryFrom<&char> for Nucleobase {
    type Error = &'static str;

    fn try_from(c: &char) -> Result<Self, Self::Error> {
        match from_letter_code(c) {
            Some(base) => Ok(base),
            None => Err("Invalid character code")
        }
    }
}

impl TryFrom<char> for Nucleobase {
    type Error = &'static str;

    fn try_from(c: char) -> Result<Self, Self::Error> { Self::try_from(&c) }
}

impl fmt::Display for Nucleobase {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

#[cfg(test)]
mod tests {
    use crate::Nucleobase;

    #[test]
    fn correct_deoxyribonucleotide_bases() {
        assert_eq!(Nucleobase::Adenine.is_deoxyribonucleotide_base(), true);
        assert_eq!(Nucleobase::Cytosine.is_deoxyribonucleotide_base(), true);
        assert_eq!(Nucleobase::Guanine.is_deoxyribonucleotide_base(), true);
        assert_eq!(Nucleobase::Thymine.is_deoxyribonucleotide_base(), true);
        assert_eq!(Nucleobase::Uracil.is_deoxyribonucleotide_base(), false);
    }

    #[test]
    fn correct_ribonucleotide_bases() {
        assert_eq!(Nucleobase::Adenine.is_ribonucleotide_base(), true);
        assert_eq!(Nucleobase::Cytosine.is_ribonucleotide_base(), true);
        assert_eq!(Nucleobase::Guanine.is_ribonucleotide_base(), true);
        assert_eq!(Nucleobase::Thymine.is_ribonucleotide_base(), false);
        assert_eq!(Nucleobase::Uracil.is_ribonucleotide_base(), true);
    }

    #[test]
    fn correct_letter_codes() {
        assert_eq!(crate::from_letter_code(& 'a'), Some(Nucleobase::Adenine));
        assert_eq!(crate::from_letter_code(& 'A'), Some(Nucleobase::Adenine));
        assert_eq!(crate::from_letter_code(& 'c'), Some(Nucleobase::Cytosine));
        assert_eq!(crate::from_letter_code(& 'C'), Some(Nucleobase::Cytosine));
        assert_eq!(crate::from_letter_code(& 'g'), Some(Nucleobase::Guanine));
        assert_eq!(crate::from_letter_code(& 'G'), Some(Nucleobase::Guanine));
        assert_eq!(crate::from_letter_code(& 't'), Some(Nucleobase::Thymine));
        assert_eq!(crate::from_letter_code(& 'T'), Some(Nucleobase::Thymine));
        assert_eq!(crate::from_letter_code(& 'u'), Some(Nucleobase::Uracil));
        assert_eq!(crate::from_letter_code(& 'U'), Some(Nucleobase::Uracil));
        assert_eq!(crate::from_letter_code(& 'n'), None);
    }
}