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
148
149
150
151
152
153
use crate::parser::Format;
use std::error::Error as StdError;
use std::fmt;
use std::io;
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct ErrorPosition {
pub line: u64,
pub id: Option<String>,
}
impl fmt::Display for ErrorPosition {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if let Some(id) = self.id.as_ref() {
write!(f, "record '{}' at ", id)?;
}
write!(f, "line {}", self.line)
}
}
#[derive(Clone, Debug, PartialEq)]
pub enum ParseErrorKind {
Io,
UnknownFormat,
InvalidStart,
InvalidSeparator,
UnequalLengths,
UnexpectedEnd,
}
#[derive(Clone, Debug, PartialEq)]
pub struct ParseError {
pub msg: String,
pub kind: ParseErrorKind,
pub position: ErrorPosition,
pub format: Option<Format>,
}
impl ParseError {
pub fn new_invalid_start(byte_found: u8, position: ErrorPosition, format: Format) -> Self {
let msg = format!(
"Expected '{}' but found '{}",
format.start_char(),
(byte_found as char).escape_default()
);
ParseError {
kind: ParseErrorKind::InvalidStart,
msg,
position,
format: Some(format),
}
}
pub fn new_invalid_separator(byte_found: u8, position: ErrorPosition) -> Self {
let msg = format!(
"Expected '+' separator but found '{}",
(byte_found as char).escape_default()
);
ParseError {
kind: ParseErrorKind::InvalidSeparator,
msg,
position,
format: Some(Format::Fastq),
}
}
pub fn new_unknown_format(byte_found: u8) -> Self {
let msg = format!(
"Expected '@' or '>' at the start of the file but found '{}'.",
(byte_found as char).escape_default()
);
ParseError {
kind: ParseErrorKind::UnknownFormat,
msg,
position: ErrorPosition::default(),
format: Some(Format::Fastq),
}
}
pub fn new_unequal_length(seq_len: usize, qual_len: usize, position: ErrorPosition) -> Self {
let msg = format!(
"Sequence length is {} but quality length is {}",
seq_len, qual_len
);
ParseError {
kind: ParseErrorKind::UnequalLengths,
msg,
position,
format: Some(Format::Fastq),
}
}
pub fn new_unexpected_end(position: ErrorPosition, format: Format) -> Self {
ParseError {
msg: String::new(),
kind: ParseErrorKind::UnexpectedEnd,
position,
format: Some(format),
}
}
}
impl fmt::Display for ParseError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.kind {
ParseErrorKind::Io => write!(f, "I/O error: {}", self.msg),
ParseErrorKind::UnequalLengths
| ParseErrorKind::InvalidStart
| ParseErrorKind::UnknownFormat
| ParseErrorKind::InvalidSeparator => write!(f, "{} ({})", self.msg, self.position),
ParseErrorKind::UnexpectedEnd => {
write!(f, "Unexpected end of input ({}).", self.position)
}
}
}
}
impl From<io::Error> for ParseError {
fn from(err: io::Error) -> ParseError {
ParseError {
msg: err.to_string(),
kind: ParseErrorKind::Io,
position: ErrorPosition::default(),
format: None,
}
}
}
impl StdError for ParseError {
fn cause(&self) -> Option<&dyn StdError> {
None
}
}