use crate::{BitSize, Result, error::WriteError};
#[derive(Clone, Copy, Default)]
pub struct SequencingRecord<'a> {
pub(crate) s_seq: &'a [u8],
pub(crate) s_qual: Option<&'a [u8]>,
pub(crate) s_header: Option<&'a [u8]>,
pub(crate) x_seq: Option<&'a [u8]>,
pub(crate) x_qual: Option<&'a [u8]>,
pub(crate) x_header: Option<&'a [u8]>,
pub(crate) flag: Option<u64>,
}
impl<'a> SequencingRecord<'a> {
#[inline]
#[must_use]
pub fn new(
s_seq: &'a [u8],
s_qual: Option<&'a [u8]>,
s_header: Option<&'a [u8]>,
x_seq: Option<&'a [u8]>,
x_qual: Option<&'a [u8]>,
x_header: Option<&'a [u8]>,
flag: Option<u64>,
) -> Self {
Self {
s_seq,
s_qual,
s_header,
x_seq,
x_qual,
x_header,
flag,
}
}
#[inline]
#[must_use]
pub fn s_seq(&self) -> &'a [u8] {
self.s_seq
}
#[inline]
#[must_use]
pub fn s_qual(&self) -> Option<&'a [u8]> {
self.s_qual
}
#[inline]
#[must_use]
pub fn s_header(&self) -> Option<&'a [u8]> {
self.s_header
}
#[inline]
#[must_use]
pub fn x_seq(&self) -> Option<&'a [u8]> {
self.x_seq
}
#[inline]
#[must_use]
pub fn x_qual(&self) -> Option<&'a [u8]> {
self.x_qual
}
#[inline]
#[must_use]
pub fn x_header(&self) -> Option<&'a [u8]> {
self.x_header
}
#[inline]
#[must_use]
pub fn flag(&self) -> Option<u64> {
self.flag
}
#[inline]
#[must_use]
pub fn configured_size_cbq(
&self,
is_paired: bool,
has_flags: bool,
has_headers: bool,
has_qualities: bool,
) -> usize {
const NUCS_PER_WORD: usize = 32;
let mut size = 0;
let s_chunks = self.s_seq.len().div_ceil(NUCS_PER_WORD);
size += s_chunks * 8;
if is_paired {
let x_chunks = self.x_seq.map_or(0, |x| x.len().div_ceil(NUCS_PER_WORD));
size += x_chunks * 8;
}
if has_flags {
size += 8; }
if has_headers {
size += self.s_header.map_or(0, <[u8]>::len);
if is_paired {
size += self.x_header.map_or(0, <[u8]>::len);
}
}
if has_qualities {
size += self.s_qual.map_or(0, <[u8]>::len);
if is_paired {
size += self.x_qual.map_or(0, <[u8]>::len);
}
}
size
}
#[inline]
#[must_use]
pub fn configured_size_vbq(
&self,
is_paired: bool,
has_flags: bool,
has_headers: bool,
has_qualities: bool,
bitsize: BitSize,
) -> usize {
let nucs_per_byte = if matches!(bitsize, BitSize::Two) {
4
} else {
2
};
let nucs_per_word = nucs_per_byte * 8;
let mut size = 0;
size += 16;
if has_flags {
size += 8;
}
let s_chunks = self.s_seq.len().div_ceil(nucs_per_word);
size += s_chunks * 8;
if is_paired {
let x_chunks = self.x_seq.map_or(0, |x| x.len().div_ceil(nucs_per_word));
size += x_chunks * 8;
}
if has_qualities {
size += self.s_qual.map_or(0, <[u8]>::len);
if is_paired {
size += self.x_qual.map_or(0, <[u8]>::len);
}
}
if has_headers {
if let Some(h) = self.s_header {
size += 8 + h.len(); }
if is_paired && let Some(h) = self.x_header {
size += 8 + h.len(); }
}
size
}
#[inline]
#[must_use]
pub fn is_paired(&self) -> bool {
self.x_seq.is_some()
}
#[inline]
#[must_use]
pub fn has_flags(&self) -> bool {
self.flag.is_some()
}
#[inline]
#[must_use]
pub fn has_headers(&self) -> bool {
self.s_header.is_some() || self.x_header.is_some()
}
#[inline]
#[must_use]
pub fn has_qualities(&self) -> bool {
self.s_qual.is_some() || self.x_qual.is_some()
}
}
#[derive(Default)]
pub struct SequencingRecordBuilder<'a> {
s_seq: Option<&'a [u8]>,
s_qual: Option<&'a [u8]>,
s_header: Option<&'a [u8]>,
x_seq: Option<&'a [u8]>,
x_qual: Option<&'a [u8]>,
x_header: Option<&'a [u8]>,
flag: Option<u64>,
}
impl<'a> SequencingRecordBuilder<'a> {
#[must_use]
pub fn s_seq(mut self, s_seq: &'a [u8]) -> Self {
self.s_seq = Some(s_seq);
self
}
#[must_use]
pub fn s_qual(mut self, s_qual: &'a [u8]) -> Self {
self.s_qual = Some(s_qual);
self
}
#[must_use]
pub fn opt_s_qual(mut self, s_qual: Option<&'a [u8]>) -> Self {
self.s_qual = s_qual;
self
}
#[must_use]
pub fn s_header(mut self, s_header: &'a [u8]) -> Self {
self.s_header = Some(s_header);
self
}
#[must_use]
pub fn opt_s_header(mut self, s_header: Option<&'a [u8]>) -> Self {
self.s_header = s_header;
self
}
#[must_use]
pub fn x_seq(mut self, x_seq: &'a [u8]) -> Self {
self.x_seq = Some(x_seq);
self
}
#[must_use]
pub fn opt_x_seq(mut self, x_seq: Option<&'a [u8]>) -> Self {
self.x_seq = x_seq;
self
}
#[must_use]
pub fn x_qual(mut self, x_qual: &'a [u8]) -> Self {
self.x_qual = Some(x_qual);
self
}
#[must_use]
pub fn opt_x_qual(mut self, x_qual: Option<&'a [u8]>) -> Self {
self.x_qual = x_qual;
self
}
#[must_use]
pub fn x_header(mut self, x_header: &'a [u8]) -> Self {
self.x_header = Some(x_header);
self
}
#[must_use]
pub fn opt_x_header(mut self, x_header: Option<&'a [u8]>) -> Self {
self.x_header = x_header;
self
}
#[must_use]
pub fn flag(mut self, flag: u64) -> Self {
self.flag = Some(flag);
self
}
#[must_use]
pub fn opt_flag(mut self, flag: Option<u64>) -> Self {
self.flag = flag;
self
}
pub fn build(self) -> Result<SequencingRecord<'a>> {
let Some(s_seq) = self.s_seq else {
return Err(WriteError::MissingSequence.into());
};
Ok(SequencingRecord {
s_seq,
s_qual: self.s_qual,
s_header: self.s_header,
x_seq: self.x_seq,
x_qual: self.x_qual,
x_header: self.x_header,
flag: self.flag,
})
}
}