Documentation
pub fn phreq_list_2_quality(baseq: &[u8]) -> Option<f32> {
    if baseq.len() == 0 {
        return None;
    }
    let length = baseq.len() as f64;
    let err_rate = baseq
        .iter()
        .map(|v| *v as f64)
        .map(|v| 10.0_f64.powf(v / -10.0_f64))
        .reduce(|acc, v| acc + v)
        .unwrap()
        / length;
    Some((1.0_f64 - err_rate) as f32)
}

pub fn phreq_list_2_quality_list(baseq: &[u8]) -> Vec<f32> {
    baseq
        .iter()
        .map(|v| *v as f64)
        .map(|v| 10.0_f64.powf(v / -10.0_f64))
        .map(|v| 1.0 - v)
        .map(|v| v as f32)
        .collect()
}

pub fn phreq_list_2_error_list(baseq: &[u8]) -> Vec<f32> {
    baseq
        .iter()
        .map(|v| *v as f64)
        .map(|v| 10.0_f64.powf(v / -10.0_f64))
        .map(|v| v as f32)
        .collect()
}

pub fn phreq2err(phreq: f64) -> f64 {
    10.0_f64.powf(phreq / -10.0_f64)
}

pub fn phreq2quality(phreq: f64) -> f64 {
    1.0 - phreq2err(phreq)
}

pub fn quality_2_phreq_f32(mut quality: f32, eps: Option<f32>) -> f32 {
    let eps = eps.unwrap_or(1e-5);
    let max_quality = 1.0_f32 - eps;

    quality = if quality > max_quality {
        max_quality
    } else {
        quality
    };
    -10.0_f32 * (1.0_f32 - quality).log10()
}

pub fn quality_2_phreq(quality: f32, eps: Option<f32>) -> u8 {
    let phreq = quality_2_phreq_f32(quality, eps);
    phreq.round() as u8
}

#[cfg(test)]
mod test {
    use crate::phreq::phreq_list_2_error_list;

    use super::{phreq2quality, phreq_list_2_quality, phreq_list_2_quality_list, quality_2_phreq};

    #[test]
    fn test_phreq_list_2_quality() {
        let quality = phreq_list_2_quality(&[20, 20, 20, 20]);
        assert!((quality.unwrap() - 0.99) < 1e-3);

        let quality = phreq_list_2_quality(&[30, 30, 30, 30]);
        assert!((quality.unwrap() - 0.999) < 1e-4);
    }

    #[test]
    fn test_quality_2_phreq() {
        let phreq = quality_2_phreq(0.99, None);
        assert_eq!(phreq, 20);

        let phreq = quality_2_phreq(0.999, None);
        assert_eq!(phreq, 30);

        let phreq = quality_2_phreq(0.9999, None);
        assert_eq!(phreq, 40);
    }

    #[test]
    fn test_phreq_list_2_quality_list() {
        let quality = phreq_list_2_quality_list(&[20, 30, 40, 50]);
        assert!((quality[0] - 0.99).abs() < 1e-6);
        assert!((quality[1] - 0.999).abs() < 1e-6);
        assert!((quality[2] - 0.9999).abs() < 1e-6);
        assert!((quality[3] - 0.99999).abs() < 1e-6);
    }

    #[test]
    fn test_phreq_list_2_err_list() {
        let quality = phreq_list_2_error_list(&[20, 30, 40, 50]);
        assert!((quality[0] - (1.0 - 0.99)).abs() < 1e-6);
        assert!((quality[1] - (1.0 - 0.999)).abs() < 1e-6);
        assert!((quality[2] - (1.0 - 0.9999)).abs() < 1e-6);
        assert!((quality[3] - (1.0 - 0.99999)).abs() < 1e-6);
    }

    #[test]
    fn test_phreq2quality() {
        let quality = phreq2quality(20.0);
        assert!((quality - 0.99).abs() < 1e-6);
    }
}