From 1162cd6610ed743065c156985e104da209485ff8 Mon Sep 17 00:00:00 2001 From: Michael Macias Date: Wed, 18 Dec 2024 15:01:27 -0600 Subject: [PATCH] vcf/io/reader: Add a header reader adapter This can be used to read the raw VCF header. `header::Reader` existed previously, but this increases its visibility and creates a public constructor for it. --- noodles-vcf/CHANGELOG.md | 8 +++++++ noodles-vcf/src/io/reader.rs | 37 ++++++++++++++++++++++++++++- noodles-vcf/src/io/reader/header.rs | 9 +++++-- 3 files changed, 51 insertions(+), 3 deletions(-) diff --git a/noodles-vcf/CHANGELOG.md b/noodles-vcf/CHANGELOG.md index 6bed0a962..ecc78f4f3 100644 --- a/noodles-vcf/CHANGELOG.md +++ b/noodles-vcf/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## Unreleased + +### Added + + * vcf/io/reader: Add a header reader adapter (`header::Reader`). + + This can be used to read the raw VCF header. + ## 0.69.0 - 2024-12-12 ### Changed diff --git a/noodles-vcf/src/io/reader.rs b/noodles-vcf/src/io/reader.rs index 03bdc06bb..d47845e5a 100644 --- a/noodles-vcf/src/io/reader.rs +++ b/noodles-vcf/src/io/reader.rs @@ -1,7 +1,7 @@ //! VCF reader and iterators. mod builder; -mod header; +pub mod header; pub(crate) mod query; pub(crate) mod record; pub mod record_buf; @@ -121,6 +121,41 @@ where } } + /// Returns a VCF header reader. + /// + /// This creates an adapter that reads at most the length of the header, i.e., all lines + /// prefixed with a `#` (number sign). + /// + /// It is more ergonomic to read and parse the header using [`Self::read_header`], but using + /// this adapter allows for control of how the header is read, e.g., to read the raw VCF + /// header. + /// + /// The position of the stream is expected to be at the start. + /// + /// # Examples + /// + /// ``` + /// # use std::io::Read; + /// use noodles_vcf as vcf; + /// + /// let data = b"##fileformat=VCFv4.3 + /// #CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO + /// sq0\t1\t.\tA\t.\t.\tPASS\t. + /// "; + /// + /// let mut reader = vcf::io::Reader::new(&data[..]); + /// let mut header_reader = reader.header_reader(); + /// + /// let mut raw_header = String::new(); + /// header_reader.read_to_string(&mut raw_header)?; + /// + /// assert_eq!(raw_header, "##fileformat=VCFv4.3\n#CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO\n"); + /// # Ok::<_, std::io::Error>(()) + /// ``` + pub fn header_reader(&mut self) -> header::Reader<'_, R> { + header::Reader::new(&mut self.inner) + } + /// Reads the VCF header. /// /// This reads all header lines prefixed with a `#` (number sign), which includes the header diff --git a/noodles-vcf/src/io/reader/header.rs b/noodles-vcf/src/io/reader/header.rs index 036ce1e02..15de3edd9 100644 --- a/noodles-vcf/src/io/reader/header.rs +++ b/noodles-vcf/src/io/reader/header.rs @@ -1,14 +1,19 @@ +//! VCF header reader. + use std::io::{self, BufRead, Read}; use crate::{header, Header}; -struct Reader<'r, R> { +/// A VCF header reader. +/// +/// This is created by calling [`super::Reader::header_reader`]. +pub struct Reader<'r, R> { inner: &'r mut R, is_eol: bool, } impl<'r, R> Reader<'r, R> { - fn new(inner: &'r mut R) -> Self { + pub(super) fn new(inner: &'r mut R) -> Self { Self { inner, is_eol: true,