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
//! 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;
enum Inner<R> {
Vcf(vcf::io::Reader<R>),
Bcf(bcf::io::Reader<R>),
}
/// A variant reader.
pub struct Reader<R> {
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),
}
}
}