Browse Source

Implement custom Error struct, remove error_chain

and fix some clippy warnings.
Johannes Hofmann 7 years ago
parent
commit
325514eb98
12 changed files with 212 additions and 96 deletions
  1. 0
    1
      Cargo.toml
  2. 1
    3
      examples/count.rs
  3. 21
    18
      src/blob.rs
  4. 13
    12
      src/block.rs
  5. 3
    3
      src/dense.rs
  6. 10
    10
      src/elements.rs
  7. 145
    0
      src/error.rs
  8. 0
    25
      src/errors.rs
  9. 2
    4
      src/lib.rs
  10. 11
    14
      src/mmap_blob.rs
  11. 1
    1
      src/reader.rs
  12. 5
    5
      src/util.rs

+ 0
- 1
Cargo.toml View File

25
 byteorder = "1.1"
25
 byteorder = "1.1"
26
 flate2 = { version = "1.0", optional = true }
26
 flate2 = { version = "1.0", optional = true }
27
 inflate = "0.4"
27
 inflate = "0.4"
28
-error-chain = "0.11"
29
 memmap = "0.6"
28
 memmap = "0.6"
30
 rayon = "1.0"
29
 rayon = "1.0"

+ 1
- 3
examples/count.rs View File

1
 // Count the number of nodes, ways and relations in a PBF file given as the
1
 // Count the number of nodes, ways and relations in a PBF file given as the
2
 // first command line argument.
2
 // first command line argument.
3
 
3
 
4
-extern crate error_chain;
5
 extern crate osmpbf;
4
 extern crate osmpbf;
6
 
5
 
7
 use osmpbf::*;
6
 use osmpbf::*;
8
-use error_chain::ChainedError;
9
 
7
 
10
 fn main() {
8
 fn main() {
11
     let arg = std::env::args_os().nth(1).expect("need a *.osm.pbf file as argument");
9
     let arg = std::env::args_os().nth(1).expect("need a *.osm.pbf file as argument");
31
             println!("Relations: {}", relations);
29
             println!("Relations: {}", relations);
32
         },
30
         },
33
         Err(e) => {
31
         Err(e) => {
34
-            println!("{}", e.display_chain().to_string());
32
+            println!("{}", e);
35
         },
33
         },
36
     }
34
     }
37
 }
35
 }

+ 21
- 18
src/blob.rs View File

5
 
5
 
6
 use block::{HeaderBlock, PrimitiveBlock};
6
 use block::{HeaderBlock, PrimitiveBlock};
7
 use byteorder::ReadBytesExt;
7
 use byteorder::ReadBytesExt;
8
-use errors::*;
8
+use error::{BlobError, Result, new_blob_error, new_protobuf_error};
9
 use proto::fileformat;
9
 use proto::fileformat;
10
 use std::fs::File;
10
 use std::fs::File;
11
 use std::io::{BufReader, Read};
11
 use std::io::{BufReader, Read};
64
 impl Blob {
64
 impl Blob {
65
     fn new(header: fileformat::BlobHeader, blob: fileformat::Blob) -> Blob {
65
     fn new(header: fileformat::BlobHeader, blob: fileformat::Blob) -> Blob {
66
         Blob {
66
         Blob {
67
-            header: header,
68
-            blob: blob
67
+            header,
68
+            blob
69
         }
69
         }
70
     }
70
     }
71
 
71
 
100
     pub fn to_headerblock(&self) -> Result<HeaderBlock> {
100
     pub fn to_headerblock(&self) -> Result<HeaderBlock> {
101
         decode_blob(&self.blob)
101
         decode_blob(&self.blob)
102
             .map(HeaderBlock::new)
102
             .map(HeaderBlock::new)
103
-            .chain_err(|| "failed to decode blob to header block")
104
     }
103
     }
105
 
104
 
106
     /// Tries to decode the blob to a `PrimitiveBlock`. This operation might involve an expensive
105
     /// Tries to decode the blob to a `PrimitiveBlock`. This operation might involve an expensive
108
     pub fn to_primitiveblock(&self) -> Result<PrimitiveBlock> {
107
     pub fn to_primitiveblock(&self) -> Result<PrimitiveBlock> {
109
         decode_blob(&self.blob)
108
         decode_blob(&self.blob)
110
             .map(PrimitiveBlock::new)
109
             .map(PrimitiveBlock::new)
111
-            .chain_err(|| "failed to decode blob to primitive block")
112
     }
110
     }
113
 }
111
 }
114
 
112
 
137
     /// ```
135
     /// ```
138
     pub fn new(reader: R) -> BlobReader<R> {
136
     pub fn new(reader: R) -> BlobReader<R> {
139
         BlobReader {
137
         BlobReader {
140
-            reader: reader,
138
+            reader,
141
             last_blob_ok: true,
139
             last_blob_ok: true,
142
         }
140
         }
143
     }
141
     }
181
             Err(e) => {
179
             Err(e) => {
182
                 match e.kind() {
180
                 match e.kind() {
183
                     ::std::io::ErrorKind::UnexpectedEof => {
181
                     ::std::io::ErrorKind::UnexpectedEof => {
182
+                        //TODO This also accepts corrupted files in the case of 1-3 available bytes
184
                         return None
183
                         return None
185
                     },
184
                     },
186
                     _ => {
185
                     _ => {
187
                         self.last_blob_ok = false;
186
                         self.last_blob_ok = false;
188
-                        return Some(Err(Error::with_chain(e, "Could not decode blob header size")));
187
+                        return Some(Err(new_blob_error(BlobError::InvalidHeaderSize)));
189
                     },
188
                     },
190
                 }
189
                 }
191
             },
190
             },
193
 
192
 
194
         if header_size >= MAX_BLOB_HEADER_SIZE {
193
         if header_size >= MAX_BLOB_HEADER_SIZE {
195
             self.last_blob_ok = false;
194
             self.last_blob_ok = false;
196
-            return Some(Err(ErrorKind::BlobHeaderTooBig(header_size).into()));
195
+            return Some(Err(new_blob_error(BlobError::HeaderTooBig{size: header_size})));
197
         }
196
         }
198
 
197
 
199
         let header: fileformat::BlobHeader = match parse_message_from_reader(&mut self.reader.by_ref().take(header_size)) {
198
         let header: fileformat::BlobHeader = match parse_message_from_reader(&mut self.reader.by_ref().take(header_size)) {
200
             Ok(header) => header,
199
             Ok(header) => header,
201
             Err(e) => {
200
             Err(e) => {
202
                 self.last_blob_ok = false;
201
                 self.last_blob_ok = false;
203
-                return Some(Err(Error::with_chain(e, "Could not decode BlobHeader")));
202
+                return Some(Err(new_protobuf_error(e, "blob header")));
204
             },
203
             },
205
         };
204
         };
206
 
205
 
208
             Ok(blob) => blob,
207
             Ok(blob) => blob,
209
             Err(e) => {
208
             Err(e) => {
210
                 self.last_blob_ok = false;
209
                 self.last_blob_ok = false;
211
-                return Some(Err(Error::with_chain(e, "Could not decode Blob")));
210
+                return Some(Err(new_protobuf_error(e, "blob content")));
212
             },
211
             },
213
         };
212
         };
214
 
213
 
222
     if blob.has_raw() {
221
     if blob.has_raw() {
223
         let size = blob.get_raw().len() as u64;
222
         let size = blob.get_raw().len() as u64;
224
         if size < MAX_BLOB_MESSAGE_SIZE {
223
         if size < MAX_BLOB_MESSAGE_SIZE {
225
-            parse_message_from_bytes(blob.get_raw()).chain_err(|| "Could not parse raw data")
224
+            parse_message_from_bytes(blob.get_raw())
225
+                .map_err(|e| new_protobuf_error(e, "raw blob data"))
226
         } else {
226
         } else {
227
-            Err(ErrorKind::BlobMessageTooBig(size).into())
227
+            Err(new_blob_error(BlobError::MessageTooBig{size}))
228
         }
228
         }
229
     } else if blob.has_zlib_data() {
229
     } else if blob.has_zlib_data() {
230
         let mut decoder = ZlibDecoder::new(blob.get_zlib_data())
230
         let mut decoder = ZlibDecoder::new(blob.get_zlib_data())
231
             .take(MAX_BLOB_MESSAGE_SIZE);
231
             .take(MAX_BLOB_MESSAGE_SIZE);
232
-        parse_message_from_reader(&mut decoder).chain_err(|| "Could not parse zlib data")
232
+        parse_message_from_reader(&mut decoder)
233
+            .map_err(|e| new_protobuf_error(e, "blob zlib data"))
233
     } else {
234
     } else {
234
-        bail!("Blob is missing fields 'raw' and 'zlib_data")
235
+        Err(new_blob_error(BlobError::Empty))
235
     }
236
     }
236
 }
237
 }
237
 
238
 
241
     if blob.has_raw() {
242
     if blob.has_raw() {
242
         let size = blob.get_raw().len() as u64;
243
         let size = blob.get_raw().len() as u64;
243
         if size < MAX_BLOB_MESSAGE_SIZE {
244
         if size < MAX_BLOB_MESSAGE_SIZE {
244
-            parse_message_from_bytes(blob.get_raw()).chain_err(|| "Could not parse raw data")
245
+            parse_message_from_bytes(blob.get_raw())
246
+                .map_err(|e| new_protobuf_error(e, "raw blob data"))
245
         } else {
247
         } else {
246
-            Err(ErrorKind::BlobMessageTooBig(size).into())
248
+            Err(new_blob_error(BlobError::MessageTooBig{size}))
247
         }
249
         }
248
     } else if blob.has_zlib_data() {
250
     } else if blob.has_zlib_data() {
249
         let mut decoder = DeflateDecoder::from_zlib(blob.get_zlib_data())
251
         let mut decoder = DeflateDecoder::from_zlib(blob.get_zlib_data())
250
             .take(MAX_BLOB_MESSAGE_SIZE);
252
             .take(MAX_BLOB_MESSAGE_SIZE);
251
-        parse_message_from_reader(&mut decoder).chain_err(|| "Could not parse zlib data")
253
+        parse_message_from_reader(&mut decoder)
254
+            .map_err(|e| new_protobuf_error(e, "blob zlib data"))
252
     } else {
255
     } else {
253
-        bail!("Blob is missing fields 'raw' and 'zlib_data")
256
+        Err(new_blob_error(BlobError::Empty))
254
     }
257
     }
255
 }
258
 }

+ 13
- 12
src/block.rs View File

2
 
2
 
3
 use dense::DenseNodeIter;
3
 use dense::DenseNodeIter;
4
 use elements::{Element, Node, Way, Relation};
4
 use elements::{Element, Node, Way, Relation};
5
-use errors::*;
5
+use error::{ErrorKind, Result, new_error};
6
 use proto::osmformat;
6
 use proto::osmformat;
7
 use std;
7
 use std;
8
 
8
 
15
 
15
 
16
 impl HeaderBlock {
16
 impl HeaderBlock {
17
     pub(crate) fn new(header: osmformat::HeaderBlock) -> HeaderBlock {
17
     pub(crate) fn new(header: osmformat::HeaderBlock) -> HeaderBlock {
18
-        HeaderBlock { header: header }
18
+        HeaderBlock { header }
19
     }
19
     }
20
 
20
 
21
     /// Returns a list of required features that a parser needs to implement to parse the following
21
     /// Returns a list of required features that a parser needs to implement to parse the following
38
 
38
 
39
 impl PrimitiveBlock {
39
 impl PrimitiveBlock {
40
     pub(crate) fn new(block: osmformat::PrimitiveBlock) -> PrimitiveBlock {
40
     pub(crate) fn new(block: osmformat::PrimitiveBlock) -> PrimitiveBlock {
41
-        PrimitiveBlock { block: block }
41
+        PrimitiveBlock { block }
42
     }
42
     }
43
 
43
 
44
     /// Returns an iterator over the elements in this `PrimitiveBlock`.
44
     /// Returns an iterator over the elements in this `PrimitiveBlock`.
92
            group: &'a osmformat::PrimitiveGroup)
92
            group: &'a osmformat::PrimitiveGroup)
93
           -> PrimitiveGroup<'a> {
93
           -> PrimitiveGroup<'a> {
94
         PrimitiveGroup {
94
         PrimitiveGroup {
95
-            block: block,
96
-            group: group,
95
+            block,
96
+            group,
97
         }
97
         }
98
     }
98
     }
99
 
99
 
142
 impl<'a> BlockElementsIter<'a> {
142
 impl<'a> BlockElementsIter<'a> {
143
     fn new(block: &'a osmformat::PrimitiveBlock) -> BlockElementsIter<'a> {
143
     fn new(block: &'a osmformat::PrimitiveBlock) -> BlockElementsIter<'a> {
144
         BlockElementsIter {
144
         BlockElementsIter {
145
-            block: block,
145
+            block,
146
             state: ElementsIterState::Group,
146
             state: ElementsIterState::Group,
147
             groups: block.get_primitivegroup().iter(),
147
             groups: block.get_primitivegroup().iter(),
148
             dense_nodes: DenseNodeIter::empty(block),
148
             dense_nodes: DenseNodeIter::empty(block),
240
 impl<'a> GroupIter<'a> {
240
 impl<'a> GroupIter<'a> {
241
     fn new(block: &'a osmformat::PrimitiveBlock) -> GroupIter<'a> {
241
     fn new(block: &'a osmformat::PrimitiveBlock) -> GroupIter<'a> {
242
         GroupIter {
242
         GroupIter {
243
-            block: block,
243
+            block,
244
             groups: block.get_primitivegroup().iter(),
244
             groups: block.get_primitivegroup().iter(),
245
         }
245
         }
246
     }
246
     }
275
            group: &'a osmformat::PrimitiveGroup)
275
            group: &'a osmformat::PrimitiveGroup)
276
           -> GroupNodeIter<'a> {
276
           -> GroupNodeIter<'a> {
277
         GroupNodeIter {
277
         GroupNodeIter {
278
-            block: block,
278
+            block,
279
             nodes: group.get_nodes().iter(),
279
             nodes: group.get_nodes().iter(),
280
         }
280
         }
281
     }
281
     }
310
            group: &'a osmformat::PrimitiveGroup)
310
            group: &'a osmformat::PrimitiveGroup)
311
           -> GroupWayIter<'a> {
311
           -> GroupWayIter<'a> {
312
         GroupWayIter {
312
         GroupWayIter {
313
-            block: block,
313
+            block,
314
             ways: group.get_ways().iter(),
314
             ways: group.get_ways().iter(),
315
         }
315
         }
316
     }
316
     }
345
            group: &'a osmformat::PrimitiveGroup)
345
            group: &'a osmformat::PrimitiveGroup)
346
           -> GroupRelationIter<'a> {
346
           -> GroupRelationIter<'a> {
347
         GroupRelationIter {
347
         GroupRelationIter {
348
-            block: block,
348
+            block,
349
             rels: group.get_relations().iter(),
349
             rels: group.get_relations().iter(),
350
         }
350
         }
351
     }
351
     }
370
 
370
 
371
 pub(crate) fn str_from_stringtable(block: &osmformat::PrimitiveBlock, index: usize) -> Result<&str> {
371
 pub(crate) fn str_from_stringtable(block: &osmformat::PrimitiveBlock, index: usize) -> Result<&str> {
372
     if let Some(vec) = block.get_stringtable().get_s().get(index) {
372
     if let Some(vec) = block.get_stringtable().get_s().get(index) {
373
+        //TODO at location to ErrorKind::Utf8
373
         std::str::from_utf8(vec)
374
         std::str::from_utf8(vec)
374
-            .chain_err(|| "failed to decode string from string table")
375
+            .map_err(|e| new_error(ErrorKind::Utf8(e)))
375
     } else {
376
     } else {
376
-        Err(ErrorKind::StringtableIndexOutOfBounds(index).into())
377
+        Err(new_error(ErrorKind::StringtableIndexOutOfBounds{index}))
377
     }
378
     }
378
 }
379
 }

+ 3
- 3
src/dense.rs View File

1
 //! Iterate over the dense nodes in a `PrimitiveGroup`
1
 //! Iterate over the dense nodes in a `PrimitiveGroup`
2
 
2
 
3
-use errors::*;
3
+use error::Result;
4
 use proto::osmformat;
4
 use proto::osmformat;
5
 use block::str_from_stringtable;
5
 use block::str_from_stringtable;
6
 use std;
6
 use std;
90
            osmdense: &'a osmformat::DenseNodes) -> DenseNodeIter<'a> {
90
            osmdense: &'a osmformat::DenseNodes) -> DenseNodeIter<'a> {
91
         let info = osmdense.get_denseinfo();
91
         let info = osmdense.get_denseinfo();
92
         DenseNodeIter {
92
         DenseNodeIter {
93
-            block: block,
93
+            block,
94
             dids: osmdense.get_id().iter(),
94
             dids: osmdense.get_id().iter(),
95
             cid: 0,
95
             cid: 0,
96
             versions: info.get_version().iter(),
96
             versions: info.get_version().iter(),
113
 
113
 
114
     pub(crate) fn empty(block: &'a osmformat::PrimitiveBlock) -> DenseNodeIter<'a> {
114
     pub(crate) fn empty(block: &'a osmformat::PrimitiveBlock) -> DenseNodeIter<'a> {
115
         DenseNodeIter {
115
         DenseNodeIter {
116
-            block: block,
116
+            block,
117
             dids: [].iter(),
117
             dids: [].iter(),
118
             cid: 0,
118
             cid: 0,
119
             versions: [].iter(),
119
             versions: [].iter(),

+ 10
- 10
src/elements.rs View File

1
 //! Nodes, ways and relations
1
 //! Nodes, ways and relations
2
 
2
 
3
-use errors::*;
3
+use error::Result;
4
 use block::str_from_stringtable;
4
 use block::str_from_stringtable;
5
 use dense::DenseNode;
5
 use dense::DenseNode;
6
 use proto::osmformat::PrimitiveBlock;
6
 use proto::osmformat::PrimitiveBlock;
36
 impl<'a> Node<'a> {
36
 impl<'a> Node<'a> {
37
     pub(crate) fn new(block: &'a PrimitiveBlock, osmnode: &'a osmformat::Node) -> Node<'a> {
37
     pub(crate) fn new(block: &'a PrimitiveBlock, osmnode: &'a osmformat::Node) -> Node<'a> {
38
         Node {
38
         Node {
39
-            block: block,
40
-            osmnode: osmnode,
39
+            block,
40
+            osmnode,
41
         }
41
         }
42
     }
42
     }
43
 
43
 
130
 impl<'a> Way<'a> {
130
 impl<'a> Way<'a> {
131
     pub(crate) fn new(block: &'a PrimitiveBlock, osmway: &'a osmformat::Way) -> Way<'a> {
131
     pub(crate) fn new(block: &'a PrimitiveBlock, osmway: &'a osmformat::Way) -> Way<'a> {
132
         Way {
132
         Way {
133
-            block: block,
134
-            osmway: osmway,
133
+            block,
134
+            osmway,
135
         }
135
         }
136
     }
136
     }
137
 
137
 
222
 impl<'a> Relation<'a> {
222
 impl<'a> Relation<'a> {
223
     pub(crate) fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> Relation<'a> {
223
     pub(crate) fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> Relation<'a> {
224
         Relation {
224
         Relation {
225
-            block: block,
226
-            osmrel: osmrel,
225
+            block,
226
+            osmrel,
227
         }
227
         }
228
     }
228
     }
229
 
229
 
372
 impl<'a> RelMemberIter<'a> {
372
 impl<'a> RelMemberIter<'a> {
373
     fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> RelMemberIter<'a> {
373
     fn new(block: &'a PrimitiveBlock, osmrel: &'a osmformat::Relation) -> RelMemberIter<'a> {
374
         RelMemberIter {
374
         RelMemberIter {
375
-            block: block,
375
+            block,
376
             role_sids: osmrel.get_roles_sid().iter(),
376
             role_sids: osmrel.get_roles_sid().iter(),
377
             member_id_deltas: osmrel.get_memids().iter(),
377
             member_id_deltas: osmrel.get_memids().iter(),
378
             member_types: osmrel.get_types().iter(),
378
             member_types: osmrel.get_types().iter(),
479
 impl<'a> Info<'a> {
479
 impl<'a> Info<'a> {
480
     fn new(block: &'a PrimitiveBlock, info: &'a osmformat::Info) -> Info<'a> {
480
     fn new(block: &'a PrimitiveBlock, info: &'a osmformat::Info) -> Info<'a> {
481
         Info {
481
         Info {
482
-            block: block,
483
-            info: info,
482
+            block,
483
+            info,
484
         }
484
         }
485
     }
485
     }
486
 
486
 

+ 145
- 0
src/error.rs View File

1
+use std::error::Error as StdError;
2
+use std::fmt;
3
+use std::io;
4
+use std::result;
5
+use std::str;
6
+use std::str::Utf8Error;
7
+
8
+use protobuf::ProtobufError;
9
+
10
+// Error data structures are modeled just like in the `csv` crate by BurntSushi.
11
+
12
+pub(crate) fn new_error(kind: ErrorKind) -> Error {
13
+    Error(Box::new(kind))
14
+}
15
+
16
+pub(crate) fn new_blob_error(kind: BlobError) -> Error {
17
+    Error(Box::new(ErrorKind::Blob(kind)))
18
+}
19
+
20
+pub(crate) fn new_protobuf_error(err: ProtobufError, location: &'static str) -> Error {
21
+    Error(Box::new(ErrorKind::Protobuf{ err, location }))
22
+}
23
+
24
+/// A type alias for `Result<T, osmpbf::Error>`.
25
+pub type Result<T> = result::Result<T, Error>;
26
+
27
+/// An error that can occur when reading PBF files.
28
+#[derive(Debug)]
29
+pub struct Error(Box<ErrorKind>);
30
+
31
+impl Error {
32
+    /// Return the specific type of this error.
33
+    pub fn kind(&self) -> &ErrorKind {
34
+        &self.0
35
+    }
36
+
37
+    /// Unwrap this error into its underlying type.
38
+    pub fn into_kind(self) -> ErrorKind {
39
+        *self.0
40
+    }
41
+}
42
+
43
+/// The specific type of an error.
44
+#[derive(Debug)]
45
+pub enum ErrorKind {
46
+    Io(io::Error),
47
+    Protobuf{err: ProtobufError, location: &'static str},
48
+    Utf8(Utf8Error),
49
+    StringtableIndexOutOfBounds{index: usize},
50
+    Blob(BlobError),
51
+
52
+    //TODO add UnexpectedPrimitiveBlock
53
+
54
+    /// Hints that destructuring should not be exhaustive.
55
+    ///
56
+    /// This enum may grow additional variants, so this makes sure clients
57
+    /// don't count on exhaustive matching. (Otherwise, adding a new variant
58
+    /// could break existing code.)
59
+    #[doc(hidden)]
60
+    __Nonexhaustive,
61
+}
62
+
63
+/// An error that occurs when decoding a blob.
64
+#[derive(Debug)]
65
+pub enum BlobError {
66
+    InvalidHeaderSize,
67
+    HeaderTooBig{size: u64},
68
+    MessageTooBig{size: u64},
69
+    Empty,
70
+    /// Hints that destructuring should not be exhaustive.
71
+    #[doc(hidden)]
72
+    __Nonexhaustive,
73
+}
74
+
75
+
76
+impl From<io::Error> for Error {
77
+    fn from(err: io::Error) -> Error {
78
+        new_error(ErrorKind::Io(err))
79
+    }
80
+}
81
+
82
+impl From<Error> for io::Error {
83
+    fn from(err: Error) -> io::Error {
84
+        io::Error::new(io::ErrorKind::Other, err)
85
+    }
86
+}
87
+
88
+impl StdError for Error {
89
+    fn description(&self) -> &str {
90
+        match *self.0 {
91
+            ErrorKind::Io(ref err) => err.description(),
92
+            ErrorKind::Protobuf{ref err, ..} => err.description(),
93
+            ErrorKind::Utf8(ref err) => err.description(),
94
+            ErrorKind::StringtableIndexOutOfBounds{..} => "stringtable index out of bounds",
95
+            ErrorKind::Blob(BlobError::InvalidHeaderSize) => "blob header size could not be decoded",
96
+            ErrorKind::Blob(BlobError::HeaderTooBig{..}) => "blob header is too big",
97
+            ErrorKind::Blob(BlobError::MessageTooBig{..}) => "blob message is too big",
98
+            ErrorKind::Blob(BlobError::Empty) => "blob is missing fields 'raw' and 'zlib_data",
99
+            _ => unreachable!(),
100
+        }
101
+    }
102
+
103
+    fn cause(&self) -> Option<&StdError> {
104
+        match *self.0 {
105
+            ErrorKind::Io(ref err) => Some(err),
106
+            ErrorKind::Protobuf{ref err, ..} => Some(err),
107
+            ErrorKind::Utf8(ref err) => Some(err),
108
+            ErrorKind::StringtableIndexOutOfBounds{..} => None,
109
+            ErrorKind::Blob(BlobError::InvalidHeaderSize) => None,
110
+            ErrorKind::Blob(BlobError::HeaderTooBig{..}) => None,
111
+            ErrorKind::Blob(BlobError::MessageTooBig{..}) => None,
112
+            ErrorKind::Blob(BlobError::Empty) => None,
113
+            _ => unreachable!(),
114
+        }
115
+    }
116
+}
117
+
118
+impl fmt::Display for Error {
119
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
120
+        match *self.0 {
121
+            ErrorKind::Io(ref err) => err.fmt(f),
122
+            ErrorKind::Protobuf{ref err, location} => {
123
+                write!(f, "protobuf error at '{}': {}", location, err)
124
+            },
125
+            ErrorKind::Utf8(ref err) => err.fmt(f),
126
+            ErrorKind::StringtableIndexOutOfBounds { index } => {
127
+                write!(f, "stringtable index out of bounds: {}", index)
128
+            },
129
+            ErrorKind::Blob(BlobError::InvalidHeaderSize) => {
130
+                write!(f, "blob header size could not be decoded")
131
+            },
132
+            ErrorKind::Blob(BlobError::HeaderTooBig { size }) => {
133
+                write!(f, "blob header is too big: {} bytes", size)
134
+            },
135
+            ErrorKind::Blob(BlobError::MessageTooBig { size }) => {
136
+                write!(f, "blob message is too big: {} bytes", size)
137
+            },
138
+            ErrorKind::Blob(BlobError::Empty) => {
139
+                write!(f, "blob is missing fields 'raw' and 'zlib_data'")
140
+            },
141
+            _ => unreachable!(),
142
+        }
143
+    }
144
+}
145
+

+ 0
- 25
src/errors.rs View File

1
-error_chain!{
2
-    foreign_links {
3
-        Io(::std::io::Error);
4
-        Protobuf(::protobuf::ProtobufError);
5
-    }
6
-
7
-    errors {
8
-        StringtableIndexOutOfBounds(index: usize) {
9
-            description("stringtable index out of bounds")
10
-            display("stringtable index out of bounds: {}", index)
11
-        }
12
-
13
-        BlobHeaderTooBig(size: u64) {
14
-            description("blob header is too big")
15
-            display("blob header is too big: {} bytes", size)
16
-        }
17
-
18
-        BlobMessageTooBig(size: u64) {
19
-            description("blob message is too big")
20
-            display("blob message is too big: {} bytes", size)
21
-        }
22
-
23
-        //TODO add UnexpectedPrimitiveBlock
24
-    }
25
-}

+ 2
- 4
src/lib.rs View File

75
 extern crate memmap;
75
 extern crate memmap;
76
 extern crate protobuf;
76
 extern crate protobuf;
77
 extern crate rayon;
77
 extern crate rayon;
78
-#[macro_use]
79
-extern crate error_chain;
80
 
78
 
81
 #[cfg(feature = "system-libz")]
79
 #[cfg(feature = "system-libz")]
82
 extern crate flate2;
80
 extern crate flate2;
89
 pub use block::*;
87
 pub use block::*;
90
 pub use dense::*;
88
 pub use dense::*;
91
 pub use elements::*;
89
 pub use elements::*;
92
-pub use errors::{Error, ErrorKind, Result, ResultExt};
90
+pub use error::{Error, ErrorKind, Result};
93
 pub use mmap_blob::*;
91
 pub use mmap_blob::*;
94
 pub use reader::*;
92
 pub use reader::*;
95
 
93
 
96
-mod errors;
94
+mod error;
97
 mod proto;
95
 mod proto;
98
 pub mod reader;
96
 pub mod reader;
99
 pub mod blob;
97
 pub mod blob;

+ 11
- 14
src/mmap_blob.rs View File

7
 use blob::{BlobDecode, BlobType, decode_blob};
7
 use blob::{BlobDecode, BlobType, decode_blob};
8
 use block::{HeaderBlock, PrimitiveBlock};
8
 use block::{HeaderBlock, PrimitiveBlock};
9
 use byteorder::ByteOrder;
9
 use byteorder::ByteOrder;
10
-use errors::*;
10
+use error::{BlobError, Result, new_blob_error, new_protobuf_error};
11
 use proto::{fileformat, osmformat};
11
 use proto::{fileformat, osmformat};
12
 use self::fileformat::BlobHeader;
12
 use self::fileformat::BlobHeader;
13
 use std::fs::File;
13
 use std::fs::File;
42
     pub unsafe fn from_file(file: &File) -> Result<Mmap> {
42
     pub unsafe fn from_file(file: &File) -> Result<Mmap> {
43
         memmap::Mmap::map(file)
43
         memmap::Mmap::map(file)
44
             .map(|m| Mmap { mmap: m })
44
             .map(|m| Mmap { mmap: m })
45
-            .chain_err(|| "Could not create memory map from file")
45
+            .map_err(|e| e.into())
46
     }
46
     }
47
 
47
 
48
     /// Creates a memory map from a given path.
48
     /// Creates a memory map from a given path.
65
         let file = File::open(&path)?;
65
         let file = File::open(&path)?;
66
         memmap::Mmap::map(&file)
66
         memmap::Mmap::map(&file)
67
             .map(|m| Mmap { mmap: m })
67
             .map(|m| Mmap { mmap: m })
68
-            .chain_err(|| format!("Could not create memory map from path {}", path.as_ref().display()))
68
+            .map_err(|e| e.into())
69
     }
69
     }
70
 
70
 
71
     /// Returns an iterator over the blobs in this memory map.
71
     /// Returns an iterator over the blobs in this memory map.
90
     /// `PrimitiveBlock`). This operation might involve an expensive decompression step.
90
     /// `PrimitiveBlock`). This operation might involve an expensive decompression step.
91
     pub fn decode(&'a self) -> Result<BlobDecode<'a>> {
91
     pub fn decode(&'a self) -> Result<BlobDecode<'a>> {
92
         let blob: fileformat::Blob = parse_message_from_bytes(self.data)
92
         let blob: fileformat::Blob = parse_message_from_bytes(self.data)
93
-            .chain_err(|| "failed to parse Blob")?;
93
+            .map_err(|e| new_protobuf_error(e, "blob content"))?;
94
         match self.header.get_field_type() {
94
         match self.header.get_field_type() {
95
             "OSMHeader" => {
95
             "OSMHeader" => {
96
                 let block = Box::new(HeaderBlock::new(decode_blob(&blob)?));
96
                 let block = Box::new(HeaderBlock::new(decode_blob(&blob)?));
139
     /// ```
139
     /// ```
140
     pub fn new(mmap: &Mmap) -> MmapBlobReader {
140
     pub fn new(mmap: &Mmap) -> MmapBlobReader {
141
         MmapBlobReader {
141
         MmapBlobReader {
142
-            mmap: mmap,
142
+            mmap,
143
             offset: 0,
143
             offset: 0,
144
             last_blob_ok: true,
144
             last_blob_ok: true,
145
         }
145
         }
156
             0 => return None,
156
             0 => return None,
157
             1 ... 3 => {
157
             1 ... 3 => {
158
                 self.last_blob_ok = false;
158
                 self.last_blob_ok = false;
159
-                let io_error = ::std::io::Error::new(
160
-                    ::std::io::ErrorKind::UnexpectedEof, "failed to parse blob header length"
161
-                );
162
-                return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
159
+                return Some(Err(new_blob_error(BlobError::InvalidHeaderSize)));
163
             },
160
             },
164
             _ => {},
161
             _ => {},
165
         }
162
         }
168
 
165
 
169
         if header_size as u64 >= ::blob::MAX_BLOB_HEADER_SIZE {
166
         if header_size as u64 >= ::blob::MAX_BLOB_HEADER_SIZE {
170
             self.last_blob_ok = false;
167
             self.last_blob_ok = false;
171
-            return Some(Err(ErrorKind::BlobHeaderTooBig(header_size as u64).into()));
168
+            return Some(Err(new_blob_error(BlobError::HeaderTooBig{size: header_size as u64})));
172
         }
169
         }
173
 
170
 
174
         if slice.len() < 4 + header_size {
171
         if slice.len() < 4 + header_size {
176
             let io_error = ::std::io::Error::new(
173
             let io_error = ::std::io::Error::new(
177
                 ::std::io::ErrorKind::UnexpectedEof, "content too short for header"
174
                 ::std::io::ErrorKind::UnexpectedEof, "content too short for header"
178
             );
175
             );
179
-            return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
176
+            return Some(Err(io_error.into()));
180
         }
177
         }
181
 
178
 
182
         let header: BlobHeader = match parse_message_from_bytes(&slice[4..(4 + header_size)]) {
179
         let header: BlobHeader = match parse_message_from_bytes(&slice[4..(4 + header_size)]) {
183
             Ok(x) => x,
180
             Ok(x) => x,
184
             Err(e) => {
181
             Err(e) => {
185
                 self.last_blob_ok = false;
182
                 self.last_blob_ok = false;
186
-                return Some(Err(e));
183
+                return Some(Err(new_protobuf_error(e, "blob header")));
187
             },
184
             },
188
         };
185
         };
189
 
186
 
195
             let io_error = ::std::io::Error::new(
192
             let io_error = ::std::io::Error::new(
196
                 ::std::io::ErrorKind::UnexpectedEof, "content too short for block data"
193
                 ::std::io::ErrorKind::UnexpectedEof, "content too short for block data"
197
             );
194
             );
198
-            return Some(Err(Error::from_kind(ErrorKind::Io(io_error))));
195
+            return Some(Err(io_error.into()));
199
         }
196
         }
200
 
197
 
201
         self.offset += chunk_size;
198
         self.offset += chunk_size;
202
 
199
 
203
         Some(Ok(MmapBlob {
200
         Some(Ok(MmapBlob {
204
-            header: header,
201
+            header,
205
             data: &slice[(4 + header_size)..chunk_size]
202
             data: &slice[(4 + header_size)..chunk_size]
206
         }))
203
         }))
207
     }
204
     }

+ 1
- 1
src/reader.rs View File

2
 
2
 
3
 use blob::{BlobDecode, BlobReader};
3
 use blob::{BlobDecode, BlobReader};
4
 use elements::Element;
4
 use elements::Element;
5
-use errors::*;
5
+use error::Result;
6
 use rayon::prelude::*;
6
 use rayon::prelude::*;
7
 use std::fs::File;
7
 use std::fs::File;
8
 use std::io::{BufReader, Read};
8
 use std::io::{BufReader, Read};

+ 5
- 5
src/util.rs View File

1
-use errors::*;
1
+use protobuf::ProtobufError;
2
 use std::io::Read;
2
 use std::io::Read;
3
 
3
 
4
 
4
 
5
-pub(crate) fn parse_message_from_bytes<M>(bytes: &[u8]) -> Result<M>
5
+pub(crate) fn parse_message_from_bytes<M>(bytes: &[u8]) -> Result<M, ProtobufError>
6
     where M: ::protobuf::Message
6
     where M: ::protobuf::Message
7
 {
7
 {
8
     let mut stream = ::protobuf::CodedInputStream::from_bytes(bytes);
8
     let mut stream = ::protobuf::CodedInputStream::from_bytes(bytes);
12
     if message.is_initialized() {
12
     if message.is_initialized() {
13
         Ok(message)
13
         Ok(message)
14
     } else {
14
     } else {
15
-        Err(::protobuf::ProtobufError::message_not_initialized("").into())
15
+        Err(::protobuf::ProtobufError::message_not_initialized(""))
16
     }
16
     }
17
 }
17
 }
18
 
18
 
19
-pub(crate) fn parse_message_from_reader<R, M>(reader: &mut R) -> Result<M>
19
+pub(crate) fn parse_message_from_reader<R, M>(reader: &mut R) -> Result<M, ProtobufError>
20
     where R: Read,
20
     where R: Read,
21
           M: ::protobuf::Message,
21
           M: ::protobuf::Message,
22
 {
22
 {
29
     if message.is_initialized() {
29
     if message.is_initialized() {
30
         Ok(message)
30
         Ok(message)
31
     } else {
31
     } else {
32
-        Err(::protobuf::ProtobufError::message_not_initialized("").into())
32
+        Err(::protobuf::ProtobufError::message_not_initialized(""))
33
     }
33
     }
34
 }
34
 }