use crate::error::DryIceError;
pub trait SeqRecordLike {
fn name(&self) -> &[u8];
fn sequence(&self) -> &[u8];
fn quality(&self) -> &[u8];
fn len(&self) -> usize {
self.sequence().len()
}
fn is_empty(&self) -> bool {
self.sequence().is_empty()
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SeqRecord {
name: Vec<u8>,
sequence: Vec<u8>,
quality: Vec<u8>,
}
impl SeqRecord {
pub fn new(name: Vec<u8>, sequence: Vec<u8>, quality: Vec<u8>) -> Result<Self, DryIceError> {
if sequence.len() != quality.len() {
return Err(DryIceError::MismatchedSequenceAndQualityLengths {
sequence_len: sequence.len(),
quality_len: quality.len(),
});
}
Ok(Self {
name,
sequence,
quality,
})
}
pub fn from_slices(name: &[u8], sequence: &[u8], quality: &[u8]) -> Result<Self, DryIceError> {
Self::new(name.to_vec(), sequence.to_vec(), quality.to_vec())
}
#[must_use]
pub fn name(&self) -> &[u8] {
&self.name
}
#[must_use]
pub fn sequence(&self) -> &[u8] {
&self.sequence
}
#[must_use]
pub fn quality(&self) -> &[u8] {
&self.quality
}
#[must_use]
pub fn into_name(self) -> Vec<u8> {
self.name
}
#[must_use]
pub fn into_sequence(self) -> Vec<u8> {
self.sequence
}
#[must_use]
pub fn into_quality(self) -> Vec<u8> {
self.quality
}
#[must_use]
pub fn into_parts(self) -> (Vec<u8>, Vec<u8>, Vec<u8>) {
(self.name, self.sequence, self.quality)
}
pub fn name_str(&self) -> Result<&str, std::str::Utf8Error> {
std::str::from_utf8(&self.name)
}
pub fn sequence_str(&self) -> Result<&str, std::str::Utf8Error> {
std::str::from_utf8(&self.sequence)
}
pub fn quality_str(&self) -> Result<&str, std::str::Utf8Error> {
std::str::from_utf8(&self.quality)
}
}
impl std::fmt::Display for SeqRecord {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let name = std::str::from_utf8(&self.name).unwrap_or("<non-utf8>");
let seq = std::str::from_utf8(&self.sequence).unwrap_or("<non-utf8>");
write!(f, "{name}\t{seq}\t({} bp)", self.sequence.len())
}
}
impl SeqRecordLike for SeqRecord {
fn name(&self) -> &[u8] {
self.name()
}
fn sequence(&self) -> &[u8] {
self.sequence()
}
fn quality(&self) -> &[u8] {
self.quality()
}
}
pub trait SeqRecordExt: SeqRecordLike {
fn to_seq_record(&self) -> Result<SeqRecord, DryIceError> {
SeqRecord::from_slices(self.name(), self.sequence(), self.quality())
}
}
impl<T: SeqRecordLike + ?Sized> SeqRecordExt for T {}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
pub struct EmptyRecord;
impl SeqRecordLike for EmptyRecord {
fn name(&self) -> &[u8] {
b""
}
fn sequence(&self) -> &[u8] {
b""
}
fn quality(&self) -> &[u8] {
b""
}
}
pub const EMPTY_RECORD: EmptyRecord = EmptyRecord;