A Rust library for reading the OpenStreetMap PBF file format (*.osm.pbf).

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