use std::{io::Read, marker::PhantomData};
use crate::{
block::{
BlockDecoder,
name::{NameCodec, OmittedNameCodec, RawNameCodec},
quality::{OmittedQualityCodec, QualityCodec, RawQualityCodec},
sequence::{OmittedSequenceCodec, RawAsciiCodec, SequenceCodec, TwoBitExactCodec},
},
error::DryIceError,
fields::{AllFields, HasKey, HasName, HasQuality, HasSequence, SelectionExpr, SelectionPlan},
format,
key::{Bytes8Key, Bytes16Key, NoRecordKey, RecordKey},
record::{SeqRecord, SeqRecordExt, SeqRecordLike},
};
#[doc(hidden)]
pub struct MissingInner;
#[doc(hidden)]
pub struct ReadAllFields;
#[doc(hidden)]
pub struct ReadSelectedFields<F>(PhantomData<F>);
pub struct SelectedDryIceReader<
R,
S = RawAsciiCodec,
Q = RawQualityCodec,
N = RawNameCodec,
K = NoRecordKey,
F = ReadAllFields,
> {
inner: DryIceReader<R, S, Q, N, K>,
_fields: PhantomData<F>,
}
pub struct SelectedRecord<
'a,
R,
S = RawAsciiCodec,
Q = RawQualityCodec,
N = RawNameCodec,
K = NoRecordKey,
F = ReadAllFields,
> {
reader: &'a DryIceReader<R, S, Q, N, K>,
_fields: PhantomData<F>,
}
pub type SelectedRecordView<'a, R, S, Q, N, K, F> = SelectedRecord<'a, R, S, Q, N, K, F>;
pub type SelectedNextRecord<'a, R, S, Q, N, K, F> =
Option<SelectedRecordView<'a, R, S, Q, N, K, F>>;
fn verify_block_codecs<S, Q, N>(
header: &crate::block::header::BlockHeader,
) -> Result<(), DryIceError>
where
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
{
if header.sequence_codec_tag != S::TYPE_TAG {
return Err(DryIceError::SequenceCodecMismatch {
expected: S::TYPE_TAG,
found: header.sequence_codec_tag,
});
}
if header.quality_codec_tag != Q::TYPE_TAG {
return Err(DryIceError::QualityCodecMismatch {
expected: Q::TYPE_TAG,
found: header.quality_codec_tag,
});
}
if header.name_codec_tag != N::TYPE_TAG {
return Err(DryIceError::NameCodecMismatch {
expected: N::TYPE_TAG,
found: header.name_codec_tag,
});
}
Ok(())
}
pub struct DryIceReaderBuilder<
R = MissingInner,
S = RawAsciiCodec,
Q = RawQualityCodec,
N = RawNameCodec,
K = NoRecordKey,
M = ReadAllFields,
> {
inner: R,
_codec: PhantomData<S>,
_quality: PhantomData<Q>,
_name: PhantomData<N>,
_key: PhantomData<K>,
_mode: PhantomData<M>,
}
impl
DryIceReaderBuilder<
MissingInner,
RawAsciiCodec,
RawQualityCodec,
RawNameCodec,
NoRecordKey,
ReadAllFields,
>
{
fn new() -> Self {
Self {
inner: MissingInner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
}
impl<S, Q, N, K, M> DryIceReaderBuilder<MissingInner, S, Q, N, K, M> {
#[must_use]
pub fn inner<R>(self, inner: R) -> DryIceReaderBuilder<R, S, Q, N, K, M> {
DryIceReaderBuilder {
inner,
_codec: self._codec,
_quality: self._quality,
_name: self._name,
_key: self._key,
_mode: self._mode,
}
}
}
impl<R, Q, N, K, M> DryIceReaderBuilder<R, RawAsciiCodec, Q, N, K, M> {
#[must_use]
pub fn sequence_codec<S: SequenceCodec>(self) -> DryIceReaderBuilder<R, S, Q, N, K, M> {
DryIceReaderBuilder {
inner: self.inner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
#[must_use]
pub fn two_bit_exact(self) -> DryIceReaderBuilder<R, TwoBitExactCodec, Q, N, K, M> {
self.sequence_codec::<TwoBitExactCodec>()
}
#[must_use]
pub fn omit_sequence(self) -> DryIceReaderBuilder<R, OmittedSequenceCodec, Q, N, K, M> {
self.sequence_codec::<OmittedSequenceCodec>()
}
}
impl<R, S, N, K, M> DryIceReaderBuilder<R, S, RawQualityCodec, N, K, M> {
#[must_use]
pub fn quality_codec<Q: QualityCodec>(self) -> DryIceReaderBuilder<R, S, Q, N, K, M> {
DryIceReaderBuilder {
inner: self.inner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
#[must_use]
pub fn omit_quality(self) -> DryIceReaderBuilder<R, S, OmittedQualityCodec, N, K, M> {
self.quality_codec::<OmittedQualityCodec>()
}
}
impl<R, S, Q, K, M> DryIceReaderBuilder<R, S, Q, RawNameCodec, K, M> {
#[must_use]
pub fn name_codec<N: NameCodec>(self) -> DryIceReaderBuilder<R, S, Q, N, K, M> {
DryIceReaderBuilder {
inner: self.inner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
#[must_use]
pub fn omit_names(self) -> DryIceReaderBuilder<R, S, Q, OmittedNameCodec, K, M> {
self.name_codec::<OmittedNameCodec>()
}
}
impl<R, S, Q, N, M> DryIceReaderBuilder<R, S, Q, N, NoRecordKey, M> {
#[must_use]
pub fn record_key<K: RecordKey>(self) -> DryIceReaderBuilder<R, S, Q, N, K, M> {
DryIceReaderBuilder {
inner: self.inner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
#[must_use]
pub fn bytes8_key(self) -> DryIceReaderBuilder<R, S, Q, N, Bytes8Key, M> {
self.record_key::<Bytes8Key>()
}
#[must_use]
pub fn bytes16_key(self) -> DryIceReaderBuilder<R, S, Q, N, Bytes16Key, M> {
self.record_key::<Bytes16Key>()
}
}
impl<R, S, Q, N, K> DryIceReaderBuilder<R, S, Q, N, K, ReadAllFields> {
#[must_use]
pub fn select<F: SelectionExpr>(
self,
_fields: F,
) -> DryIceReaderBuilder<R, S, Q, N, K, ReadSelectedFields<F>> {
DryIceReaderBuilder {
inner: self.inner,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
_mode: PhantomData,
}
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec>
DryIceReaderBuilder<R, S, Q, N, NoRecordKey, ReadAllFields>
{
pub fn build(mut self) -> Result<DryIceReader<R, S, Q, N, NoRecordKey>, DryIceError> {
format::read_file_header(&mut self.inner)?;
Ok(DryIceReader {
inner: self.inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K: RecordKey>
DryIceReaderBuilder<R, S, Q, N, K, ReadAllFields>
{
pub fn build(mut self) -> Result<DryIceReader<R, S, Q, N, K>, DryIceError> {
format::read_file_header(&mut self.inner)?;
Ok(DryIceReader {
inner: self.inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, F: SelectionPlan>
DryIceReaderBuilder<R, S, Q, N, NoRecordKey, ReadSelectedFields<F>>
{
pub fn build(
mut self,
) -> Result<SelectedDryIceReader<R, S, Q, N, NoRecordKey, F>, DryIceError> {
format::read_file_header(&mut self.inner)?;
Ok(SelectedDryIceReader {
inner: DryIceReader {
inner: self.inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
},
_fields: PhantomData,
})
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K: RecordKey, F: SelectionPlan>
DryIceReaderBuilder<R, S, Q, N, K, ReadSelectedFields<F>>
{
pub fn build(mut self) -> Result<SelectedDryIceReader<R, S, Q, N, K, F>, DryIceError> {
format::read_file_header(&mut self.inner)?;
Ok(SelectedDryIceReader {
inner: DryIceReader {
inner: self.inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
},
_fields: PhantomData,
})
}
}
pub struct DryIceReader<
R,
S = RawAsciiCodec,
Q = RawQualityCodec,
N = RawNameCodec,
K = NoRecordKey,
> {
inner: R,
current_block: Option<BlockDecoder>,
_codec: PhantomData<S>,
_quality: PhantomData<Q>,
_name: PhantomData<N>,
_key: PhantomData<K>,
}
impl DryIceReader<MissingInner, RawAsciiCodec, RawQualityCodec, RawNameCodec, NoRecordKey> {
#[must_use]
pub fn builder() -> DryIceReaderBuilder<
MissingInner,
RawAsciiCodec,
RawQualityCodec,
RawNameCodec,
NoRecordKey,
ReadAllFields,
> {
DryIceReaderBuilder::new()
}
}
impl<R: Read> DryIceReader<R, RawAsciiCodec, RawQualityCodec, RawNameCodec, NoRecordKey> {
pub fn new(mut inner: R) -> Result<Self, DryIceError> {
format::read_file_header(&mut inner)?;
Ok(Self {
inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
pub fn with_two_bit_exact(
mut inner: R,
) -> Result<
DryIceReader<R, TwoBitExactCodec, RawQualityCodec, RawNameCodec, NoRecordKey>,
DryIceError,
> {
format::read_file_header(&mut inner)?;
Ok(DryIceReader {
inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
pub fn with_codecs<S: SequenceCodec, Q: QualityCodec, N: NameCodec>(
mut inner: R,
) -> Result<DryIceReader<R, S, Q, N, NoRecordKey>, DryIceError> {
format::read_file_header(&mut inner)?;
Ok(DryIceReader {
inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
pub fn with_record_key<K2: RecordKey>(
mut inner: R,
) -> Result<DryIceReader<R, RawAsciiCodec, RawQualityCodec, RawNameCodec, K2>, DryIceError>
{
format::read_file_header(&mut inner)?;
Ok(DryIceReader {
inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
pub fn with_bytes8_key(
inner: R,
) -> Result<DryIceReader<R, RawAsciiCodec, RawQualityCodec, RawNameCodec, Bytes8Key>, DryIceError>
{
Self::with_record_key::<Bytes8Key>(inner)
}
pub fn with_bytes16_key(
inner: R,
) -> Result<
DryIceReader<R, RawAsciiCodec, RawQualityCodec, RawNameCodec, Bytes16Key>,
DryIceError,
> {
Self::with_record_key::<Bytes16Key>(inner)
}
}
impl<R: Read> DryIceReader<R> {
pub fn open<S: SequenceCodec, Q: QualityCodec, N: NameCodec, K: RecordKey>(
mut inner: R,
) -> Result<DryIceReader<R, S, Q, N, K>, DryIceError> {
format::read_file_header(&mut inner)?;
Ok(DryIceReader {
inner,
current_block: None,
_codec: PhantomData,
_quality: PhantomData,
_name: PhantomData,
_key: PhantomData,
})
}
}
impl<R, S, Q, N, K, F> SelectedDryIceReader<R, S, Q, N, K, F>
where
R: Read,
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
F: SelectionPlan,
{
pub fn next_record(&mut self) -> Result<SelectedNextRecord<'_, R, S, Q, N, K, F>, DryIceError> {
if self.inner.next_record_prepared::<F>()? {
Ok(Some(SelectedRecord {
reader: &self.inner,
_fields: PhantomData,
}))
} else {
Ok(None)
}
}
}
impl<R, S, Q, N, K, F> SelectedRecord<'_, R, S, Q, N, K, F>
where
R: Read,
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
F: SelectionExpr + HasName,
{
#[must_use]
pub fn name(&self) -> &[u8] {
self.reader.name()
}
}
impl<R, S, Q, N, K, F> SelectedRecord<'_, R, S, Q, N, K, F>
where
R: Read,
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
F: SelectionExpr + HasSequence,
{
#[must_use]
pub fn sequence(&self) -> &[u8] {
self.reader.sequence()
}
}
impl<R, S, Q, N, K, F> SelectedRecord<'_, R, S, Q, N, K, F>
where
R: Read,
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
F: SelectionExpr + HasQuality,
{
#[must_use]
pub fn quality(&self) -> &[u8] {
self.reader.quality()
}
}
impl<R, S, Q, N, K, F> SelectedRecord<'_, R, S, Q, N, K, F>
where
R: Read,
S: SequenceCodec,
Q: QualityCodec,
N: NameCodec,
K: RecordKey,
F: SelectionExpr + HasKey,
{
pub fn record_key(&self) -> Result<K, DryIceError> {
self.reader.record_key()
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K: RecordKey>
DryIceReader<R, S, Q, N, K>
{
pub fn record_key(&self) -> Result<K, DryIceError> {
let block = self
.current_block
.as_ref()
.ok_or(DryIceError::MissingRecordKeySection)?;
block.verify_record_key::<K>()?;
K::decode_from(block.current_record_key_bytes()?)
}
pub fn next_key(&mut self) -> Result<Option<K>, DryIceError> {
if self.next_record()? {
Ok(Some(self.record_key()?))
} else {
Ok(None)
}
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K> DryIceReader<R, S, Q, N, K> {
fn next_record_prepared<P>(&mut self) -> Result<bool, DryIceError>
where
P: SelectionPlan,
{
if let Some(block) = &mut self.current_block
&& block.advance::<S, Q, N, P>()?
{
return Ok(true);
}
loop {
if let Some(header) = format::read_block_header(&mut self.inner)? {
verify_block_codecs::<S, Q, N>(&header)?;
let mut decoder = BlockDecoder::from_header_and_reader(header, &mut self.inner)?;
if decoder.advance::<S, Q, N, P>()? {
self.current_block = Some(decoder);
return Ok(true);
}
} else {
self.current_block = None;
return Ok(false);
}
}
}
pub fn next_record(&mut self) -> Result<bool, DryIceError> {
self.next_record_prepared::<AllFields>()
}
pub fn into_records(self) -> DryIceRecords<R, S, Q, N, K> {
DryIceRecords { reader: self }
}
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K> SeqRecordLike
for DryIceReader<R, S, Q, N, K>
{
fn name(&self) -> &[u8] {
self.current_block
.as_ref()
.expect("name() called with no current record")
.current_name()
}
fn sequence(&self) -> &[u8] {
self.current_block
.as_ref()
.expect("sequence() called with no current record")
.current_sequence()
}
fn quality(&self) -> &[u8] {
self.current_block
.as_ref()
.expect("quality() called with no current record")
.current_quality()
}
}
pub struct DryIceRecords<
R,
S = RawAsciiCodec,
Q = RawQualityCodec,
N = RawNameCodec,
K = NoRecordKey,
> {
reader: DryIceReader<R, S, Q, N, K>,
}
impl<R: Read, S: SequenceCodec, Q: QualityCodec, N: NameCodec, K> Iterator
for DryIceRecords<R, S, Q, N, K>
{
type Item = Result<SeqRecord, DryIceError>;
fn next(&mut self) -> Option<Self::Item> {
match self.reader.next_record() {
Ok(true) => Some(self.reader.to_seq_record()),
Ok(false) => None,
Err(e) => Some(Err(e)),
}
}
}