rustyhmmer 0.1.1

Pure-Rust HMMER3 hmmsearch with byte-identical --tblout output
Documentation


use crate::alphabet::AminoMap;




pub struct Seq {
    pub name: String,
    pub desc: String,
    pub dsq: Vec<u8>,
}

impl Seq {
    
    pub fn len(&self) -> usize {
        self.dsq.len().saturating_sub(2)
    }
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn from_amino(name: impl Into<String>, desc: impl Into<String>, aa: &str) -> Self {
        Seq {
            name: name.into(),
            desc: desc.into(),
            dsq: AminoMap::new().digitize(aa.as_bytes()),
        }
    }
}

pub fn digitize_amino<'a, I>(records: I) -> Vec<Seq>
where
    I: IntoIterator<Item = (&'a str, &'a str)>,
{
    let map = AminoMap::new();
    records
        .into_iter()
        .map(|(name, aa)| Seq {
            name: name.to_string(),
            desc: String::new(),
            dsq: map.digitize(aa.as_bytes()),
        })
        .collect()
}


pub fn read_fasta(path: &str) -> std::io::Result<Vec<Seq>> {
    use std::io::BufRead;
    let f = std::fs::File::open(path)?;
    let map = AminoMap::new();
    let mut out = Vec::new();
    let mut name = String::new();
    let mut desc = String::new();
    let mut buf: Vec<u8> = Vec::new();
    let mut have = false;

    let flush = |name: &str, desc: &str, buf: &[u8], out: &mut Vec<Seq>, map: &AminoMap| {
        if !name.is_empty() || !buf.is_empty() {
            out.push(Seq {
                name: name.to_string(),
                desc: desc.to_string(),
                dsq: map.digitize(buf),
            });
        }
    };

    for line in std::io::BufReader::new(f).lines() {
        let line = line?;
        if let Some(hdr) = line.strip_prefix('>') {
            if have {
                flush(&name, &desc, &buf, &mut out, &map);
                buf.clear();
            }
            have = true;
            let hdr = hdr.trim();
            match hdr.split_once(char::is_whitespace) {
                Some((n, d)) => {
                    name = n.to_string();
                    desc = d.trim().to_string();
                }
                None => {
                    name = hdr.to_string();
                    desc = String::new();
                }
            }
        } else {
            buf.extend(line.trim().bytes());
        }
    }
    if have {
        flush(&name, &desc, &buf, &mut out, &map);
    }
    Ok(out)
}