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)
}