rsvart 0.1.5

A small library for representing genomic variants and regions.
Documentation
use crate::SvartError;
use std::convert::TryFrom;

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Strand {
    Forward,
    Reverse,
}

impl Strand {
    pub fn is_forward(&self) -> bool {
        *self == Strand::Forward
    }

    pub fn is_reverse(&self) -> bool {
        *self == Strand::Reverse
    }

    pub fn opposite(&self) -> Strand {
        match *self {
            Strand::Reverse => Strand::Forward,
            Strand::Forward => Strand::Reverse,
        }
    }
}

impl TryFrom<char> for Strand {
    type Error = SvartError;

    fn try_from(value: char) -> Result<Self, Self::Error> {
        match value {
            '+' => Ok(Strand::Forward),
            '-' => Ok(Strand::Reverse),
            _ => Err(SvartError::IllegalValueError(
                "Could not parse value for strand.",
            )),
        }
    }
}

impl TryFrom<&str> for Strand {
    type Error = SvartError;

    fn try_from(value: &str) -> Result<Self, Self::Error> {
        match value.to_uppercase().as_str() {
            "POS" | "POSITIVE" | "FWD" | "FORWARD" => Ok(Strand::Forward),
            "NEG" | "NEGATIVE" | "REV" | "REVERSE" => Ok(Strand::Reverse),
            _ => Err(SvartError::IllegalValueError(
                "Could not parse value for strand.",
            )),
        }
    }
}

impl std::fmt::Display for Strand {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        match *self {
            Strand::Forward => write!(f, "+"),
            Strand::Reverse => write!(f, "-"),
        }
    }
}

#[cfg(test)]
mod test {
    use super::Strand;
    use crate::SvartError;
    use rstest::rstest;
    use std::convert::TryFrom;

    #[rstest]
    #[case(Strand::Forward, true)]
    #[case(Strand::Reverse, false)]
    fn test_is_positive(#[case] input: Strand, #[case] expected: bool) {
        assert_eq!(input.is_forward(), expected);
    }

    #[rstest]
    #[case(Strand::Reverse, true)]
    #[case(Strand::Forward, false)]
    fn test_is_negative(#[case] input: Strand, #[case] expected: bool) {
        assert_eq!(input.is_reverse(), expected);
    }

    #[rstest]
    #[case(Strand::Reverse, "-")]
    #[case(Strand::Forward, "+")]
    fn test_correct_symbol(#[case] input: Strand, #[case] expected: String) {
        assert_eq!(format!("{}", input), expected)
    }

    #[rstest]
    #[case('-', Strand::Reverse)]
    #[case('+', Strand::Forward)]
    fn test_correct_strand_char_pass(#[case] input: char, #[case] expected: Strand) {
        assert_eq!(Strand::try_from(input).unwrap(), expected);
    }

    #[rstest]
    #[case(
        ":",
        SvartError::IllegalValueError("Could not parse value for strand.")
    )]
    fn test_correct_strand_char_fail(#[case] input: char, #[case] expected: SvartError) {
        assert_eq!(Strand::try_from(input).unwrap_err(), expected);
    }

    #[rstest]
    #[case("pos", Strand::Forward)]
    #[case("neg", Strand::Reverse)]
    #[case("positive", Strand::Forward)]
    #[case("negative", Strand::Reverse)]
    fn test_correct_strand_string_pass(#[case] input: &str, #[case] expected: Strand) {
        assert_eq!(Strand::try_from(input).unwrap(), expected);
    }

    #[rstest]
    #[case(
        "notaastrand",
        SvartError::IllegalValueError("Could not parse value for strand.")
    )]
    fn test_correct_strand_string_fail(#[case] input: &str, #[case] expected: SvartError) {
        assert_eq!(Strand::try_from(input).unwrap_err(), expected);
    }

    #[rstest]
    #[case(Strand::Reverse, Strand::Forward)]
    #[case(Strand::Forward, Strand::Reverse)]
    fn test_opposite_strand(#[case] input: Strand, #[case] expected: Strand) {
        assert_eq!(input.opposite(), expected)
    }
}