1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
//! Variant reader.
pub(crate) mod builder;
use std::io::{self, BufRead};
use noodles_bcf as bcf;
use noodles_vcf::{self as vcf, variant::io::Read};
pub use self::builder::Builder;
use crate::variant::Record;
pub(crate) enum Inner<R> {
Vcf(vcf::io::Reader<R>),
Bcf(bcf::io::Reader<R>),
}
/// A variant reader.
pub struct Reader<R> {
pub(crate) inner: Inner<R>,
}
impl<R> Reader<R>
where
R: BufRead,
{
/// Reads and parses a variant header.
///
/// # Examples
///
/// ```
/// use noodles_util::variant::io::reader::Builder;
///
/// let data = b"##fileformat=VCFv4.5
/// #CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO
/// ";
///
/// let mut reader = Builder::default().build_from_reader(&data[..])?;
/// let _header = reader.read_header()?;
/// # Ok::<_, std::io::Error>(())
/// ```
pub fn read_header(&mut self) -> io::Result<vcf::Header> {
match &mut self.inner {
Inner::Vcf(reader) => reader.read_variant_header(),
Inner::Bcf(reader) => reader.read_variant_header(),
}
}
/// Reads a variant record.
///
/// # Examples
///
/// ```
/// use noodles_util::variant::{self, io::reader::Builder};
///
/// let data = b"##fileformat=VCFv4.5
/// #CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO
/// ";
///
/// let mut reader = Builder::default().build_from_reader(&data[..])?;
/// let header = reader.read_header()?;
///
/// let mut record = variant::Record::default();
///
/// while reader.read_record(&mut record)? != 0 {
/// // ...
/// }
/// # Ok::<_, std::io::Error>(())
/// ```
pub fn read_record(&mut self, record: &mut Record) -> io::Result<usize> {
match &mut self.inner {
Inner::Vcf(reader) => {
if !matches!(record, Record::Vcf(_)) {
*record = Record::Vcf(vcf::Record::default());
}
if let Record::Vcf(r) = record {
reader.read_record(r)
} else {
unreachable!();
}
}
Inner::Bcf(reader) => {
if !matches!(record, Record::Bcf(_)) {
*record = Record::Bcf(bcf::Record::default());
}
if let Record::Bcf(r) = record {
reader.read_record(r)
} else {
unreachable!();
}
}
}
}
/// Returns an iterator over records starting from the current stream position.
///
/// # Examples
///
/// ```
/// use noodles_util::variant::io::reader::Builder;
///
/// let data = b"##fileformat=VCFv4.5
/// #CHROM\tPOS\tID\tREF\tALT\tQUAL\tFILTER\tINFO
/// ";
///
/// let mut reader = Builder::default().build_from_reader(&data[..])?;
/// let header = reader.read_header()?;
///
/// let mut records = reader.records(&header);
///
/// for result in records {
/// let _record = result?;
/// // ...
/// }
/// # Ok::<_, std::io::Error>(())
/// ```
pub fn records<'a>(
&'a mut self,
header: &'a vcf::Header,
) -> impl Iterator<Item = io::Result<Box<dyn vcf::variant::Record>>> + 'a {
match &mut self.inner {
Inner::Vcf(reader) => reader.variant_records(header),
Inner::Bcf(reader) => reader.variant_records(header),
}
}
}
impl<'a> Reader<Box<dyn BufRead + 'a>> {
/// Creates a variant reader.
///
/// This attempts to autodetect the compression method and format of the input.
///
/// ```
/// # use std::io;
/// use noodles_util::variant;
/// let mut reader = variant::io::Reader::new(io::empty())?;
/// # Ok::<_, io::Error>(())
/// ```
pub fn new<R>(reader: R) -> io::Result<Self>
where
R: BufRead + 'a,
{
Builder::default().build_from_reader(reader)
}
}