Skip to content

Commit 9b42b08

Browse files
danieldkDaniël de Kok
authored andcommitted
Improve error handling
- `Error::context`: mark the inner error as the error source. This allows a downstream error handler (e.g. anyhow) to format the error chain nicely. - Rename `Error::Shape` to `Error::MatrixShape` to narrow down the scope of the variant. Mark the shape error as the error source. - Split `Error::Io` into `Error::{read, write}`. Mark the wrapped `io::Error` as the error source. - Do not use debug representations of values in errors, we want their string representations instead. - Remove the `Error` suffix from some variants. They are part of an error enum, we know that they are errors :^).
1 parent 87e3eb6 commit 9b42b08

File tree

16 files changed

+289
-264
lines changed

16 files changed

+289
-264
lines changed

src/chunks/io.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ impl ChunkIdentifier {
3434
{
3535
let chunk_id = read
3636
.read_u32::<LittleEndian>()
37-
.map_err(|e| Error::io_error("Cannot read chunk identifier", e))?;
37+
.map_err(|e| Error::read_error("Cannot read chunk identifier", e))?;
3838
let chunk_id = ChunkIdentifier::try_from(chunk_id)?;
3939
if chunk_id != identifier {
4040
return Err(Error::Format(format!(
@@ -107,7 +107,7 @@ macro_rules! typeid_impl {
107107
{
108108
let type_id = read
109109
.read_u32::<LittleEndian>()
110-
.map_err(|e| Error::io_error("Cannot read type identifier", e))?;
110+
.map_err(|e| Error::read_error("Cannot read type identifier", e))?;
111111
if type_id != Self::type_id() {
112112
return Err(Error::Format(format!(
113113
"Invalid type, expected: {}, got: {}",
@@ -187,18 +187,18 @@ impl WriteChunk for Header {
187187
{
188188
write
189189
.write_all(&MAGIC)
190-
.map_err(|e| Error::io_error("Cannot write magic", e))?;
190+
.map_err(|e| Error::write_error("Cannot write magic", e))?;
191191
write
192192
.write_u32::<LittleEndian>(MODEL_VERSION)
193-
.map_err(|e| Error::io_error("Cannot write model version", e))?;
193+
.map_err(|e| Error::write_error("Cannot write model version", e))?;
194194
write
195195
.write_u32::<LittleEndian>(self.chunk_identifiers.len() as u32)
196-
.map_err(|e| Error::io_error("Cannot write chunk identifiers length", e))?;
196+
.map_err(|e| Error::write_error("Cannot write chunk identifiers length", e))?;
197197

198198
for &identifier in &self.chunk_identifiers {
199199
write
200200
.write_u32::<LittleEndian>(identifier as u32)
201-
.map_err(|e| Error::io_error("Cannot write chunk identifier", e))?;
201+
.map_err(|e| Error::write_error("Cannot write chunk identifier", e))?;
202202
}
203203

204204
Ok(())
@@ -213,7 +213,7 @@ impl ReadChunk for Header {
213213
// Magic and version ceremony.
214214
let mut magic = [0u8; 4];
215215
read.read_exact(&mut magic)
216-
.map_err(|e| Error::io_error("Cannot read magic", e))?;
216+
.map_err(|e| Error::read_error("Cannot read magic", e))?;
217217

218218
if magic != MAGIC {
219219
return Err(Error::Format(format!(
@@ -224,7 +224,7 @@ impl ReadChunk for Header {
224224

225225
let version = read
226226
.read_u32::<LittleEndian>()
227-
.map_err(|e| Error::io_error("Cannot read model version", e))?;
227+
.map_err(|e| Error::read_error("Cannot read model version", e))?;
228228
if version != MODEL_VERSION {
229229
return Err(Error::Format(format!(
230230
"Unknown finalfusion version: {}",
@@ -235,13 +235,13 @@ impl ReadChunk for Header {
235235
// Read chunk identifiers.
236236
let chunk_identifiers_len = read
237237
.read_u32::<LittleEndian>()
238-
.map_err(|e| Error::io_error("Cannot read chunk identifiers length", e))?
238+
.map_err(|e| Error::read_error("Cannot read chunk identifiers length", e))?
239239
as usize;
240240
let mut chunk_identifiers = Vec::with_capacity(chunk_identifiers_len);
241241
for _ in 0..chunk_identifiers_len {
242242
let identifier = read
243243
.read_u32::<LittleEndian>()
244-
.map_err(|e| Error::io_error("Cannot read chunk identifier", e))?;
244+
.map_err(|e| Error::read_error("Cannot read chunk identifier", e))?;
245245
let chunk_identifier = ChunkIdentifier::try_from(identifier)?;
246246
chunk_identifiers.push(chunk_identifier);
247247
}

src/chunks/metadata.rs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,15 @@ impl ReadChunk for Metadata {
5353
ChunkIdentifier::ensure_chunk_type(read, ChunkIdentifier::Metadata)?;
5454

5555
// Read chunk length.
56-
let chunk_len =
57-
read.read_u64::<LittleEndian>()
58-
.map_err(|e| Error::io_error("Cannot read chunk length", e))? as usize;
56+
let chunk_len = read
57+
.read_u64::<LittleEndian>()
58+
.map_err(|e| Error::read_error("Cannot read chunk length", e))?
59+
as usize;
5960

6061
// Read TOML data.
6162
let mut buf = vec![0; chunk_len];
6263
read.read_exact(&mut buf)
63-
.map_err(|e| Error::io_error("Cannot read TOML metadata", e))?;
64+
.map_err(|e| Error::read_error("Cannot read TOML metadata", e))?;
6465
let buf_str = String::from_utf8(buf)
6566
.map_err(|e| Error::Format(format!("TOML metadata contains invalid UTF-8: {}", e)))
6667
.map_err(Error::from)?;
@@ -87,13 +88,13 @@ impl WriteChunk for Metadata {
8788

8889
write
8990
.write_u32::<LittleEndian>(self.chunk_identifier() as u32)
90-
.map_err(|e| Error::io_error("Cannot write metadata chunk identifier", e))?;
91+
.map_err(|e| Error::write_error("Cannot write metadata chunk identifier", e))?;
9192
write
9293
.write_u64::<LittleEndian>(metadata_str.len() as u64)
93-
.map_err(|e| Error::io_error("Cannot write metadata length", e))?;
94+
.map_err(|e| Error::write_error("Cannot write metadata length", e))?;
9495
write
9596
.write_all(metadata_str.as_bytes())
96-
.map_err(|e| Error::io_error("Cannot write metadata", e))?;
97+
.map_err(|e| Error::write_error("Cannot write metadata", e))?;
9798

9899
Ok(())
99100
}

src/chunks/norms.rs

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -59,26 +59,26 @@ impl ReadChunk for NdNorms {
5959

6060
// Read and discard chunk length.
6161
read.read_u64::<LittleEndian>()
62-
.map_err(|e| Error::io_error("Cannot read norms chunk length", e))?;
62+
.map_err(|e| Error::read_error("Cannot read norms chunk length", e))?;
6363

6464
let len = read
6565
.read_u64::<LittleEndian>()
66-
.map_err(|e| Error::io_error("Cannot read norms vector length", e))?
66+
.map_err(|e| Error::read_error("Cannot read norms vector length", e))?
6767
.try_into()
6868
.map_err(|_| Error::Overflow)?;
6969

7070
f32::ensure_data_type(read)?;
7171

7272
let n_padding =
7373
padding::<f32>(read.seek(SeekFrom::Current(0)).map_err(|e| {
74-
Error::io_error("Cannot get file position for computing padding", e)
74+
Error::read_error("Cannot get file position for computing padding", e)
7575
})?);
7676
read.seek(SeekFrom::Current(n_padding as i64))
77-
.map_err(|e| Error::io_error("Cannot skip padding", e))?;
77+
.map_err(|e| Error::read_error("Cannot skip padding", e))?;
7878

7979
let mut data = Array1::zeros((len,));
8080
read.read_f32_into::<LittleEndian>(data.as_slice_mut().unwrap())
81-
.map_err(|e| Error::io_error("Cannot read norms", e))?;
81+
.map_err(|e| Error::read_error("Cannot read norms", e))?;
8282

8383
Ok(NdNorms::new(data))
8484
}
@@ -95,11 +95,10 @@ impl WriteChunk for NdNorms {
9595
{
9696
write
9797
.write_u32::<LittleEndian>(ChunkIdentifier::NdNorms as u32)
98-
.map_err(|e| Error::io_error("Cannot write norms chunk identifier", e))?;
99-
let n_padding =
100-
padding::<f32>(write.seek(SeekFrom::Current(0)).map_err(|e| {
101-
Error::io_error("Cannot get file position for computing padding", e)
102-
})?);
98+
.map_err(|e| Error::write_error("Cannot write norms chunk identifier", e))?;
99+
let n_padding = padding::<f32>(write.seek(SeekFrom::Current(0)).map_err(|e| {
100+
Error::write_error("Cannot get file position for computing padding", e)
101+
})?);
103102

104103
// Chunk size: len (u64), type id (u32), padding ([0,4) bytes), vector.
105104
let chunk_len = size_of::<u64>()
@@ -108,23 +107,23 @@ impl WriteChunk for NdNorms {
108107
+ (self.len() * size_of::<f32>());
109108
write
110109
.write_u64::<LittleEndian>(chunk_len as u64)
111-
.map_err(|e| Error::io_error("Cannot write norms chunk length", e))?;
110+
.map_err(|e| Error::write_error("Cannot write norms chunk length", e))?;
112111
write
113112
.write_u64::<LittleEndian>(self.len() as u64)
114-
.map_err(|e| Error::io_error("Cannot write norms vector length", e))?;
113+
.map_err(|e| Error::write_error("Cannot write norms vector length", e))?;
115114
write
116115
.write_u32::<LittleEndian>(f32::type_id())
117-
.map_err(|e| Error::io_error("Cannot write norms vector type identifier", e))?;
116+
.map_err(|e| Error::write_error("Cannot write norms vector type identifier", e))?;
118117

119118
let padding = vec![0; n_padding as usize];
120119
write
121120
.write_all(&padding)
122-
.map_err(|e| Error::io_error("Cannot write padding", e))?;
121+
.map_err(|e| Error::write_error("Cannot write padding", e))?;
123122

124123
for &val in self.iter() {
125124
write
126125
.write_f32::<LittleEndian>(val)
127-
.map_err(|e| Error::io_error("Cannot write norm", e))?;
126+
.map_err(|e| Error::write_error("Cannot write norm", e))?;
128127
}
129128

130129
Ok(())

src/chunks/storage/array.rs

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -116,33 +116,33 @@ mod mmap {
116116

117117
// Read and discard chunk length.
118118
read.read_u64::<LittleEndian>()
119-
.map_err(|e| Error::io_error("Cannot read embedding matrix chunk length", e))?;
119+
.map_err(|e| Error::read_error("Cannot read embedding matrix chunk length", e))?;
120120

121121
let rows = read
122122
.read_u64::<LittleEndian>()
123123
.map_err(|e| {
124-
Error::io_error("Cannot read number of rows of the embedding matrix", e)
124+
Error::read_error("Cannot read number of rows of the embedding matrix", e)
125125
})?
126126
.try_into()
127127
.map_err(|_| Error::Overflow)?;
128128
let cols = read.read_u32::<LittleEndian>().map_err(|e| {
129-
Error::io_error("Cannot read number of columns of the embedding matrix", e)
129+
Error::read_error("Cannot read number of columns of the embedding matrix", e)
130130
})? as usize;
131131
let shape = Ix2(rows, cols);
132132

133133
// The components of the embedding matrix should be of type f32.
134134
f32::ensure_data_type(read)?;
135135

136136
let n_padding = padding::<f32>(read.seek(SeekFrom::Current(0)).map_err(|e| {
137-
Error::io_error("Cannot get file position for computing padding", e)
137+
Error::read_error("Cannot get file position for computing padding", e)
138138
})?);
139139
read.seek(SeekFrom::Current(n_padding as i64))
140-
.map_err(|e| Error::io_error("Cannot skip padding", e))?;
140+
.map_err(|e| Error::read_error("Cannot skip padding", e))?;
141141

142142
// Set up memory mapping.
143143
let matrix_len = shape.size() * size_of::<f32>();
144144
let offset = read.seek(SeekFrom::Current(0)).map_err(|e| {
145-
Error::io_error(
145+
Error::read_error(
146146
"Cannot get file position for memory mapping embedding matrix",
147147
e,
148148
)
@@ -153,12 +153,12 @@ mod mmap {
153153
.offset(offset)
154154
.len(matrix_len)
155155
.map(&*read.get_ref())
156-
.map_err(|e| Error::io_error("Cannot memory map embedding matrix", e))?
156+
.map_err(|e| Error::read_error("Cannot memory map embedding matrix", e))?
157157
};
158158

159159
// Position the reader after the matrix.
160160
read.seek(SeekFrom::Current(matrix_len as i64))
161-
.map_err(|e| Error::io_error("Cannot skip embedding matrix", e))?;
161+
.map_err(|e| Error::read_error("Cannot skip embedding matrix", e))?;
162162

163163
Ok(MmapArray { map, shape })
164164
}
@@ -199,11 +199,10 @@ impl NdArray {
199199
{
200200
write
201201
.write_u32::<LittleEndian>(ChunkIdentifier::NdArray as u32)
202-
.map_err(|e| Error::io_error("Cannot write embedding matrix chunk identifier", e))?;
203-
let n_padding =
204-
padding::<f32>(write.seek(SeekFrom::Current(0)).map_err(|e| {
205-
Error::io_error("Cannot get file position for computing padding", e)
206-
})?);
202+
.map_err(|e| Error::write_error("Cannot write embedding matrix chunk identifier", e))?;
203+
let n_padding = padding::<f32>(write.seek(SeekFrom::Current(0)).map_err(|e| {
204+
Error::write_error("Cannot get file position for computing padding", e)
205+
})?);
207206
// Chunk size: rows (u64), columns (u32), type id (u32),
208207
// padding ([0,4) bytes), matrix.
209208
let chunk_len = size_of::<u64>()
@@ -213,20 +212,20 @@ impl NdArray {
213212
+ (data.nrows() * data.ncols() * size_of::<f32>());
214213
write
215214
.write_u64::<LittleEndian>(chunk_len as u64)
216-
.map_err(|e| Error::io_error("Cannot write embedding matrix chunk length", e))?;
215+
.map_err(|e| Error::write_error("Cannot write embedding matrix chunk length", e))?;
217216
write
218217
.write_u64::<LittleEndian>(data.nrows() as u64)
219218
.map_err(|e| {
220-
Error::io_error("Cannot write number of rows of the embedding matrix", e)
219+
Error::write_error("Cannot write number of rows of the embedding matrix", e)
221220
})?;
222221
write
223222
.write_u32::<LittleEndian>(data.ncols() as u32)
224223
.map_err(|e| {
225-
Error::io_error("Cannot write number of columns of the embedding matrix", e)
224+
Error::write_error("Cannot write number of columns of the embedding matrix", e)
226225
})?;
227226
write
228227
.write_u32::<LittleEndian>(f32::type_id())
229-
.map_err(|e| Error::io_error("Cannot write embedding matrix type identifier", e))?;
228+
.map_err(|e| Error::write_error("Cannot write embedding matrix type identifier", e))?;
230229

231230
// Write padding, such that the embedding matrix starts on at
232231
// a multiple of the size of f32 (4 bytes). This is necessary
@@ -242,13 +241,13 @@ impl NdArray {
242241
let padding = vec![0; n_padding as usize];
243242
write
244243
.write_all(&padding)
245-
.map_err(|e| Error::io_error("Cannot write padding", e))?;
244+
.map_err(|e| Error::write_error("Cannot write padding", e))?;
246245

247246
for row in data.outer_iter() {
248247
for col in row.iter() {
249-
write
250-
.write_f32::<LittleEndian>(*col)
251-
.map_err(|e| Error::io_error("Cannot write embedding matrix component", e))?;
248+
write.write_f32::<LittleEndian>(*col).map_err(|e| {
249+
Error::write_error("Cannot write embedding matrix component", e)
250+
})?;
252251
}
253252
}
254253

@@ -311,30 +310,32 @@ impl ReadChunk for NdArray {
311310

312311
// Read and discard chunk length.
313312
read.read_u64::<LittleEndian>()
314-
.map_err(|e| Error::io_error("Cannot read embedding matrix chunk length", e))?;
313+
.map_err(|e| Error::read_error("Cannot read embedding matrix chunk length", e))?;
315314

316315
let rows = read
317316
.read_u64::<LittleEndian>()
318-
.map_err(|e| Error::io_error("Cannot read number of rows of the embedding matrix", e))?
317+
.map_err(|e| {
318+
Error::read_error("Cannot read number of rows of the embedding matrix", e)
319+
})?
319320
.try_into()
320321
.map_err(|_| Error::Overflow)?;
321322
let cols = read.read_u32::<LittleEndian>().map_err(|e| {
322-
Error::io_error("Cannot read number of columns of the embedding matrix", e)
323+
Error::read_error("Cannot read number of columns of the embedding matrix", e)
323324
})? as usize;
324325

325326
// The components of the embedding matrix should be of type f32.
326327
f32::ensure_data_type(read)?;
327328

328329
let n_padding =
329330
padding::<f32>(read.seek(SeekFrom::Current(0)).map_err(|e| {
330-
Error::io_error("Cannot get file position for computing padding", e)
331+
Error::read_error("Cannot get file position for computing padding", e)
331332
})?);
332333
read.seek(SeekFrom::Current(n_padding as i64))
333-
.map_err(|e| Error::io_error("Cannot skip padding", e))?;
334+
.map_err(|e| Error::read_error("Cannot skip padding", e))?;
334335

335336
let mut data = Array2::zeros((rows, cols));
336337
read.read_f32_into::<LittleEndian>(data.as_slice_mut().unwrap())
337-
.map_err(|e| Error::io_error("Cannot read embedding matrix", e))?;
338+
.map_err(|e| Error::read_error("Cannot read embedding matrix", e))?;
338339

339340
Ok(NdArray { inner: data })
340341
}

0 commit comments

Comments
 (0)