Skip to main content

dino_seq/
lib.rs

1#![warn(missing_docs)]
2//! Low-allocation FASTQ and FASTA parsing.
3//!
4//! Dino Seq is a library core for downstream scientific tools that need
5//! low-allocation streams of ordinary FASTQ records and multiline FASTA
6//! records. The default crate is the raw parser core; gzip and BGZF transports
7//! are explicit feature opt-ins.
8//!
9//! The default feature set builds on stable Rust with no compression
10//! dependencies. SIMD acceleration is available through the explicit `simd`
11//! feature on stable Rust targets that expose supported `std::arch` intrinsics.
12//!
13//! # Choosing an entry point
14//!
15//! Use [`FastqReader`] or [`FastaReader`] directly over a concrete
16//! [`std::fs::File`] for raw-file hot paths. Use [`count_fastq_read`] for
17//! count/stat workloads that do not need record views. Use [`visit_fastq_bytes`]
18//! when a complete FASTQ byte buffer is already resident in memory. Use
19//! [`open_fastq`], [`open_fastq_with_config`], [`open_fasta`], or
20//! [`open_fasta_with_config`] when file-path convenience and optional
21//! gzip/BGZF magic detection are worth the boxed transport. Use
22//! [`PairedFastqReader`] or [`open_paired_fastq`] for ordered R1/R2 streams. Use
23//! [`visit_fasta_bytes`] for resident multiline FASTA, and
24//! [`visit_two_line_fasta_bytes`] or [`visit_two_line_fasta_read`] for strict
25//! canonical two-line FASTA fast paths.
26//!
27//! # Scope
28//!
29//! Dino Seq parses four-line FASTQ records. It validates ordered paired-end
30//! reads in separate R1/R2 streams or adjacent interleaved records, but it does
31//! not synchronize reordered mates. It does not trim adapters, filter reads,
32//! align reads, or generate quality-control reports.
33//!
34//! # Lifetimes and allocation
35//!
36//! Batches borrow from the reader's reusable storage. A [`FastqBatch`] or
37//! [`FastaBatch`] is valid until the next mutable reader call. Clone or copy
38//! record data if it must outlive the batch. This design keeps the parser
39//! low-allocation, but it means callers should process each batch before
40//! advancing the reader.
41//!
42//! # Feature flags
43//!
44//! - `gzip` enables ordinary gzip auto-detection and streaming decode.
45//! - `bgzf` enables BGZF readers, writers, indexing, and adaptive parallel
46//!   decoding.
47//! - `libdeflate` enables optional libdeflate BGZF backends.
48//! - `gzip-libdeflate` enables `gzip` plus `libdeflate` for explicit buffered
49//!   gzip openers.
50//! - `mmap` enables resident file visitors backed by memory maps.
51//! - `transport` enables both `gzip` and `bgzf` for callers that want the old
52//!   all-transport convenience build.
53//! - `simd` enables stable `std::arch` packing paths where supported.
54//!
55//! # Example
56//!
57//! ```
58//! use dino_seq::FastqReader;
59//!
60//! let data = b"@r1\nACGT\n+\nIIII\n";
61//! let mut reader = FastqReader::new(&data[..]);
62//! let mut records = 0;
63//!
64//! while let Some(batch) = reader.next_batch()? {
65//!     for record in batch.records() {
66//!         assert_eq!(record.seq(), b"ACGT");
67//!         records += 1;
68//!     }
69//! }
70//!
71//! assert_eq!(records, 1);
72//! # Ok::<(), dino_seq::FastqError>(())
73//! ```
74//!
75//! # Paired reads
76//!
77//! ```
78//! use dino_seq::PairedFastqReader;
79//!
80//! let r1 = b"@frag/1\nACGT\n+\nIIII\n";
81//! let r2 = b"@frag/2\nTGCA\n+\nJJJJ\n";
82//! let mut reader = PairedFastqReader::new(&r1[..], &r2[..]);
83//! let batch = reader.next_pair_batch()?.expect("one paired batch");
84//! let pair = batch.pairs().next().expect("one read pair");
85//!
86//! assert_eq!(pair.pair_id(), b"frag");
87//! assert_eq!(pair.first().seq(), b"ACGT");
88//! assert_eq!(pair.second().seq(), b"TGCA");
89//! # Ok::<(), dino_seq::FastqError>(())
90//! ```
91
92#[cfg(feature = "bgzf")]
93mod bgzf;
94mod error;
95mod fasta;
96mod fastq;
97mod fastq_frame;
98#[cfg(feature = "mmap")]
99mod mmap;
100/// Base/quality packing and trusted four-line FASTQ pack paths.
101///
102/// The high-level FASTQ readers expose borrowed records. This module provides
103/// the lower-level side-channel representation used when downstream code wants
104/// packed two-bit bases, ambiguity masks, and Phred+33 summaries without
105/// allocating an owned record per read.
106pub mod pack;
107mod source;
108
109#[cfg(feature = "bgzf")]
110pub use bgzf::{
111    BGZF_EOF_BLOCK, BgzfAutoReader, BgzfDecodedBlock, BgzfDecodedBlockReader, BgzfDeflateBackend,
112    BgzfIndex, BgzfIndexEntry, BgzfInflateBackend, BgzfParallelConfig, BgzfParallelReader,
113    BgzfPipelineMetrics, BgzfPipelineMetricsSnapshot, BgzfReader, BgzfSeekReader,
114    BgzfVirtualOffset, BgzfWriter, build_bgzf_index, build_bgzf_index_strict,
115    compress_bgzf_parallel, compress_bgzf_parallel_with_deflate_backend, decompress_bgzf_parallel,
116    decompress_bgzf_parallel_with_inflate_backend,
117};
118pub use error::{FastqError, FastqPosition, Result};
119#[cfg(feature = "bgzf")]
120pub use fasta::{BgzfFastaReferenceChunks, BgzfIndexedFastaReader, build_fasta_index_bgzf};
121pub use fasta::{
122    FastaBatch, FastaConfig, FastaIndex, FastaIndexEntry, FastaPartition, FastaPartitionConfig,
123    FastaReader, FastaRecord, FastaRecordRef, FastaRecordSink, FastaReferenceChunk,
124    FastaReferenceChunkRef, FastaReferenceChunkSink, FastaReferenceChunks, FastaShape, FastaStats,
125    FastaVisitRecord, IndexedFastaReader, OwnedFastaBatch, OwnedFastaRecord, build_fasta_index,
126    count_fasta_bytes, count_fasta_read, count_two_line_fasta_bytes, count_two_line_fasta_read,
127    detect_fasta_shape, plan_fasta_partitions, visit_fasta_bytes, visit_fasta_bytes_auto,
128    visit_two_line_fasta_bytes, visit_two_line_fasta_read,
129};
130pub use fastq::{
131    FastqBatch, FastqChunkConfig, FastqChunkSinkExt, FastqChunkStats, FastqConfig, FastqPair,
132    FastqReader, FastqRecord, FastqRecordSink, FastqStats, FastqVisitRecord, InterleavedPairs,
133    PairValidation, PairedFastqBatch, PairedFastqPairs, PairedFastqReader, PairedRecords,
134    PairingMode, RecordRef, count_fastq_bytes, count_fastq_read, count_fastq_read_with_config,
135    paired_records, strip_pair_suffix, visit_fastq_bytes,
136};
137#[cfg(feature = "mmap")]
138pub use mmap::{count_fasta_mmap, count_fastq_mmap, visit_fasta_mmap, visit_fastq_mmap};
139pub use source::{
140    DetectedInputKind, detect_file_input_kind, open_fasta, open_fasta_for_reference,
141    open_fasta_with_config, open_fastq, open_fastq_with_config, open_paired_fastq,
142    open_paired_fastq_with_config, open_paired_fastq_with_configs,
143};
144#[cfg(all(feature = "gzip", feature = "libdeflate"))]
145pub use source::{
146    LibdeflateGzipLimits, open_fasta_gzip_libdeflate, open_fasta_gzip_libdeflate_with_config,
147    open_fasta_gzip_libdeflate_with_limits, open_fastq_gzip_libdeflate,
148    open_fastq_gzip_libdeflate_with_config, open_fastq_gzip_libdeflate_with_limits,
149};
150#[cfg(feature = "bgzf")]
151pub use source::{
152    open_fastq_bgzf_adaptive, open_fastq_bgzf_flate2, open_fastq_bgzf_parallel,
153    open_fastq_bgzf_parallel_with_backend, open_fastq_bgzf_parallel_with_config,
154    open_fastq_bgzf_parallel_with_options, open_fastq_bgzf_with_backend,
155};