osmpbf/
error.rs

1use std::error::Error as StdError;
2use std::fmt;
3use std::io;
4use std::result;
5use std::str;
6use std::str::Utf8Error;
7
8use protobuf::Error as ProtobufError;
9
10// Error data structures are modeled just like in the `csv` crate by BurntSushi.
11
12pub(crate) fn new_error(kind: ErrorKind) -> Error {
13    Error(Box::new(kind))
14}
15
16pub(crate) fn new_blob_error(kind: BlobError) -> Error {
17    Error(Box::new(ErrorKind::Blob(kind)))
18}
19
20pub(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>`.
25pub type Result<T> = result::Result<T, Error>;
26
27/// An error that can occur when reading PBF files.
28#[derive(Debug)]
29pub struct Error(Box<ErrorKind>);
30
31impl 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#[non_exhaustive]
45#[derive(Debug)]
46pub enum ErrorKind {
47    /// An error for I/O operations.
48    Io(io::Error),
49    /// An error that occurs when decoding a protobuf message.
50    Protobuf {
51        err: ProtobufError,
52        location: &'static str,
53    },
54    /// The stringtable contains an entry at `index` that could not be decoded to a valid UTF-8
55    /// string.
56    StringtableUtf8 { err: Utf8Error, index: usize },
57    /// An element contains an out-of-bounds index to the stringtable.
58    StringtableIndexOutOfBounds { index: usize },
59    /// An error that occurs when decoding `Blob`s.
60    Blob(BlobError),
61    //TODO add UnexpectedPrimitiveBlock
62}
63
64/// An error that occurs when decoding a blob.
65#[non_exhaustive]
66#[derive(Debug)]
67pub enum BlobError {
68    /// Header size could not be decoded to a u32.
69    InvalidHeaderSize,
70    /// Blob header is bigger than [`MAX_BLOB_HEADER_SIZE`](blob/MAX_BLOB_HEADER_SIZE.v.html).
71    HeaderTooBig {
72        /// Blob header size in bytes.
73        size: u64,
74    },
75    /// Blob content is bigger than [`MAX_BLOB_MESSAGE_SIZE`](blob/MAX_BLOB_MESSAGE_SIZE.v.html).
76    MessageTooBig {
77        /// Blob content size in bytes.
78        size: u64,
79    },
80    /// The blob is empty because the `raw` and `zlib-data` fields are missing.
81    Empty,
82}
83
84impl From<io::Error> for Error {
85    fn from(err: io::Error) -> Error {
86        new_error(ErrorKind::Io(err))
87    }
88}
89
90impl From<Error> for io::Error {
91    fn from(err: Error) -> io::Error {
92        io::Error::other(err)
93    }
94}
95
96impl StdError for Error {
97    fn description(&self) -> &str {
98        match *self.0 {
99            ErrorKind::Io(ref err, ..) => {
100                use std::io::ErrorKind;
101                match err.kind() {
102                    ErrorKind::NotFound => "io error: not found",
103                    ErrorKind::PermissionDenied => "io error: permission denied",
104                    ErrorKind::ConnectionRefused => "io error: connection refused",
105                    ErrorKind::ConnectionReset => "io error: connection reset",
106                    ErrorKind::ConnectionAborted => "io error: connection aborted",
107                    ErrorKind::NotConnected => "io error: not connected",
108                    ErrorKind::AddrInUse => "io error: address in use",
109                    ErrorKind::AddrNotAvailable => "io error: address not available",
110                    ErrorKind::BrokenPipe => "io error: broken pipe",
111                    ErrorKind::AlreadyExists => "io error: already exists",
112                    ErrorKind::WouldBlock => "io error: would block",
113                    ErrorKind::InvalidInput => "io error: invalid input",
114                    ErrorKind::InvalidData => "io error: invalid data",
115                    ErrorKind::TimedOut => "io error: timed out",
116                    ErrorKind::WriteZero => "io error: write zero",
117                    ErrorKind::Interrupted => "io error: interrupted",
118                    ErrorKind::Other => "io error: other",
119                    ErrorKind::UnexpectedEof => "io error: unexpected EOF",
120                    _ => "io error",
121                }
122            }
123            ErrorKind::Protobuf { .. } => "protobuf error",
124            ErrorKind::StringtableUtf8 { .. } => "UTF-8 error in stringtable",
125            ErrorKind::StringtableIndexOutOfBounds { .. } => "stringtable index out of bounds",
126            ErrorKind::Blob(BlobError::InvalidHeaderSize) => {
127                "blob header size could not be decoded"
128            }
129            ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => "blob header is too big",
130            ErrorKind::Blob(BlobError::MessageTooBig { .. }) => "blob message is too big",
131            ErrorKind::Blob(BlobError::Empty) => "blob is missing fields 'raw' and 'zlib_data",
132        }
133    }
134
135    fn cause(&self) -> Option<&dyn StdError> {
136        match *self.0 {
137            ErrorKind::Io(ref err) => Some(err),
138            ErrorKind::Protobuf { ref err, .. } => Some(err),
139            ErrorKind::StringtableUtf8 { ref err, .. } => Some(err),
140            ErrorKind::StringtableIndexOutOfBounds { .. } => None,
141            ErrorKind::Blob(BlobError::InvalidHeaderSize) => None,
142            ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => None,
143            ErrorKind::Blob(BlobError::MessageTooBig { .. }) => None,
144            ErrorKind::Blob(BlobError::Empty) => None,
145        }
146    }
147}
148
149impl fmt::Display for Error {
150    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
151        match *self.0 {
152            ErrorKind::Io(ref err) => err.fmt(f),
153            ErrorKind::Protobuf { ref err, location } => {
154                write!(f, "protobuf error at '{location}': {err}")
155            }
156            ErrorKind::StringtableUtf8 { ref err, index } => {
157                write!(f, "invalid UTF-8 at string table index {index}: {err}")
158            }
159            ErrorKind::StringtableIndexOutOfBounds { index } => {
160                write!(f, "stringtable index out of bounds: {index}")
161            }
162            ErrorKind::Blob(BlobError::InvalidHeaderSize) => {
163                write!(f, "blob header size could not be decoded")
164            }
165            ErrorKind::Blob(BlobError::HeaderTooBig { size }) => {
166                write!(f, "blob header is too big: {size} bytes")
167            }
168            ErrorKind::Blob(BlobError::MessageTooBig { size }) => {
169                write!(f, "blob message is too big: {size} bytes")
170            }
171            ErrorKind::Blob(BlobError::Empty) => {
172                write!(f, "blob is missing fields 'raw' and 'zlib_data'")
173            }
174        }
175    }
176}