use std::error::Error as StdError; use std::fmt; use std::io; use std::result; use std::str; use std::str::Utf8Error; use protobuf::ProtobufError; // Error data structures are modeled just like in the `csv` crate by BurntSushi. pub(crate) fn new_error(kind: ErrorKind) -> Error { Error(Box::new(kind)) } pub(crate) fn new_blob_error(kind: BlobError) -> Error { Error(Box::new(ErrorKind::Blob(kind))) } pub(crate) fn new_protobuf_error(err: ProtobufError, location: &'static str) -> Error { Error(Box::new(ErrorKind::Protobuf { err, location })) } /// A type alias for `Result`. pub type Result = result::Result; /// An error that can occur when reading PBF files. #[derive(Debug)] pub struct Error(Box); impl Error { /// Return the specific type of this error. pub fn kind(&self) -> &ErrorKind { &self.0 } /// Unwrap this error into its underlying type. pub fn into_kind(self) -> ErrorKind { *self.0 } } /// The specific type of an error. #[derive(Debug)] pub enum ErrorKind { /// An error for I/O operations. Io(io::Error), /// An error that occurs when decoding a protobuf message. Protobuf { err: ProtobufError, location: &'static str, }, /// The stringtable contains an entry at `index` that could not be decoded to a valid UTF-8 /// string. StringtableUtf8 { err: Utf8Error, index: usize }, /// An element contains an out-of-bounds index to the stringtable. StringtableIndexOutOfBounds { index: usize }, /// An error that occurs when decoding `Blob`s. Blob(BlobError), //TODO add UnexpectedPrimitiveBlock /// Hints that destructuring should not be exhaustive. /// /// This enum may grow additional variants, so this makes sure clients /// don't count on exhaustive matching. (Otherwise, adding a new variant /// could break existing code.) #[doc(hidden)] __Nonexhaustive, } /// An error that occurs when decoding a blob. #[derive(Debug)] pub enum BlobError { /// Header size could not be decoded to a u32. InvalidHeaderSize, /// Blob header is bigger than [`MAX_BLOB_HEADER_SIZE`](blob/MAX_BLOB_HEADER_SIZE.v.html). HeaderTooBig { /// Blob header size in bytes. size: u64, }, /// Blob content is bigger than [`MAX_BLOB_MESSAGE_SIZE`](blob/MAX_BLOB_MESSAGE_SIZE.v.html). MessageTooBig { /// Blob content size in bytes. size: u64, }, /// The blob is empty because the `raw` and `zlib-data` fields are missing. Empty, /// Hints that destructuring should not be exhaustive. #[doc(hidden)] __Nonexhaustive, } impl From for Error { fn from(err: io::Error) -> Error { new_error(ErrorKind::Io(err)) } } impl From for io::Error { fn from(err: Error) -> io::Error { io::Error::new(io::ErrorKind::Other, err) } } impl StdError for Error { fn description(&self) -> &str { match *self.0 { ErrorKind::Io(ref err) => err.description(), ErrorKind::Protobuf { ref err, .. } => err.description(), ErrorKind::StringtableUtf8 { ref err, .. } => err.description(), ErrorKind::StringtableIndexOutOfBounds { .. } => "stringtable index out of bounds", ErrorKind::Blob(BlobError::InvalidHeaderSize) => { "blob header size could not be decoded" } ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => "blob header is too big", ErrorKind::Blob(BlobError::MessageTooBig { .. }) => "blob message is too big", ErrorKind::Blob(BlobError::Empty) => "blob is missing fields 'raw' and 'zlib_data", _ => unreachable!(), } } fn cause(&self) -> Option<&dyn StdError> { match *self.0 { ErrorKind::Io(ref err) => Some(err), ErrorKind::Protobuf { ref err, .. } => Some(err), ErrorKind::StringtableUtf8 { ref err, .. } => Some(err), ErrorKind::StringtableIndexOutOfBounds { .. } => None, ErrorKind::Blob(BlobError::InvalidHeaderSize) => None, ErrorKind::Blob(BlobError::HeaderTooBig { .. }) => None, ErrorKind::Blob(BlobError::MessageTooBig { .. }) => None, ErrorKind::Blob(BlobError::Empty) => None, _ => unreachable!(), } } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self.0 { ErrorKind::Io(ref err) => err.fmt(f), ErrorKind::Protobuf { ref err, location } => { write!(f, "protobuf error at '{}': {}", location, err) } ErrorKind::StringtableUtf8 { ref err, index } => { write!(f, "invalid UTF-8 at string table index {}: {}", index, err) } ErrorKind::StringtableIndexOutOfBounds { index } => { write!(f, "stringtable index out of bounds: {}", index) } ErrorKind::Blob(BlobError::InvalidHeaderSize) => { write!(f, "blob header size could not be decoded") } ErrorKind::Blob(BlobError::HeaderTooBig { size }) => { write!(f, "blob header is too big: {} bytes", size) } ErrorKind::Blob(BlobError::MessageTooBig { size }) => { write!(f, "blob message is too big: {} bytes", size) } ErrorKind::Blob(BlobError::Empty) => { write!(f, "blob is missing fields 'raw' and 'zlib_data'") } _ => unreachable!(), } } }