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

reader.rs 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. //! High level reader interface
  2. use blob::{BlobDecode, BlobReader};
  3. use elements::Element;
  4. use errors::*;
  5. use rayon::prelude::*;
  6. use std::fs::File;
  7. use std::io::{BufReader, Read};
  8. use std::path::Path;
  9. /// A reader for PBF files that gives access to the stored elements: nodes, ways and relations.
  10. #[derive(Clone, Debug)]
  11. pub struct ElementReader<R: Read> {
  12. blob_iter: BlobReader<R>,
  13. }
  14. impl<R: Read> ElementReader<R> {
  15. /// Creates a new `ElementReader`.
  16. ///
  17. /// # Example
  18. /// ```
  19. /// use osmpbf::*;
  20. ///
  21. /// # fn foo() -> Result<()> {
  22. /// let f = std::fs::File::open("tests/test.osm.pbf")?;
  23. /// let buf_reader = std::io::BufReader::new(f);
  24. ///
  25. /// let reader = ElementReader::new(buf_reader);
  26. ///
  27. /// # Ok(())
  28. /// # }
  29. /// ```
  30. pub fn new(reader: R) -> ElementReader<R> {
  31. ElementReader {
  32. blob_iter: BlobReader::new(reader),
  33. }
  34. }
  35. /// Decodes the PBF structure sequentially and calls the given closure on each element.
  36. /// Consider using `par_map_reduce` instead if you need better performance.
  37. ///
  38. /// # Errors
  39. /// Returns the first Error encountered while parsing the PBF structure.
  40. ///
  41. /// # Example
  42. /// ```
  43. /// use osmpbf::*;
  44. ///
  45. /// # fn foo() -> Result<()> {
  46. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  47. /// let mut ways = 0_u64;
  48. ///
  49. /// // Increment the counter by one for each way.
  50. /// reader.for_each(|element| {
  51. /// if let Element::Way(_) = element {
  52. /// ways += 1;
  53. /// }
  54. /// })?;
  55. ///
  56. /// println!("Number of ways: {}", ways);
  57. ///
  58. /// # Ok(())
  59. /// # }
  60. /// ```
  61. pub fn for_each<F>(self, mut f: F) -> Result<()>
  62. where F: for<'a> FnMut(Element<'a>) {
  63. let blobs = self.blob_iter.collect::<Result<Vec<_>>>()?;
  64. //TODO do something useful with header blocks
  65. for blob in &blobs {
  66. match blob.decode() {
  67. Ok(BlobDecode::OsmHeader(_)) | Ok(BlobDecode::Unknown(_)) => {},
  68. Ok(BlobDecode::OsmData(block)) => {
  69. block.for_each_element(&mut f);
  70. },
  71. Err(e) => return Err(e),
  72. }
  73. }
  74. Ok(())
  75. }
  76. /// Parallel map/reduce. Decodes the PBF structure in parallel, calls the closure `map_op` on
  77. /// each element and then reduces the number of results to one item with the closure
  78. /// `reduce_op`. Similarly to the `init` argument in the `fold` method on iterators, the
  79. /// `identity` closure should produce an identity value that is inserted into `reduce_op` when
  80. /// necessary. The number of times that this identity value is inserted should not alter the
  81. /// result.
  82. ///
  83. /// # Errors
  84. /// Returns the first Error encountered while parsing the PBF structure.
  85. ///
  86. /// # Example
  87. /// ```
  88. /// use osmpbf::*;
  89. ///
  90. /// # fn foo() -> Result<()> {
  91. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  92. ///
  93. /// // Count the ways
  94. /// let ways = reader.par_map_reduce(
  95. /// |element| {
  96. /// match element {
  97. /// Element::Way(_) => 1,
  98. /// _ => 0,
  99. /// }
  100. /// },
  101. /// || 0_u64, // Zero is the identity value for addition
  102. /// |a, b| a + b // Sum the partial results
  103. /// )?;
  104. ///
  105. /// println!("Number of ways: {}", ways);
  106. /// # Ok(())
  107. /// # }
  108. /// ```
  109. pub fn par_map_reduce<MP, RD, ID, T>(self, map_op: MP, identity: ID, reduce_op: RD) -> Result<T>
  110. where MP: for<'a> Fn(Element<'a>) -> T + Sync + Send,
  111. RD: Fn(T, T) -> T + Sync + Send,
  112. ID: Fn() -> T + Sync + Send,
  113. T: Send,
  114. {
  115. let blobs = self.blob_iter.collect::<Result<Vec<_>>>()?;
  116. blobs.into_par_iter().map(|blob| {
  117. match blob.decode() {
  118. Ok(BlobDecode::OsmHeader(_)) | Ok(BlobDecode::Unknown(_)) => {
  119. Ok(identity())
  120. },
  121. Ok(BlobDecode::OsmData(block)) => {
  122. let dnodes = block.groups()
  123. .flat_map(|g| g.dense_nodes())
  124. .map(|dn| map_op(Element::DenseNode(dn)));
  125. let nodes = block.groups()
  126. .flat_map(|g| g.nodes())
  127. .map(|n| map_op(Element::Node(n)));
  128. let ways = block.groups()
  129. .flat_map(|g| g.ways())
  130. .map(|w| map_op(Element::Way(w)));
  131. let rels = block.groups()
  132. .flat_map(|g| g.relations())
  133. .map(|r| map_op(Element::Relation(r)));
  134. Ok(dnodes.chain(nodes)
  135. .chain(ways)
  136. .chain(rels)
  137. .fold(identity(), |a, b| reduce_op(a, b)))
  138. },
  139. Err(e) => Err(e),
  140. }
  141. }).reduce(|| Ok(identity()), |a, b| {
  142. match (a, b) {
  143. (Ok(x), Ok(y)) => Ok(reduce_op(x, y)),
  144. (x, y) => x.and(y),
  145. }
  146. })
  147. }
  148. }
  149. impl ElementReader<BufReader<File>> {
  150. /// Tries to open the file at the given path and constructs an `ElementReader` from this.
  151. ///
  152. /// # Errors
  153. /// Returns the same errors that `std::fs::File::open` returns.
  154. ///
  155. /// # Example
  156. /// ```
  157. /// use osmpbf::*;
  158. ///
  159. /// # fn foo() -> Result<()> {
  160. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  161. /// # Ok(())
  162. /// # }
  163. /// ```
  164. pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self>
  165. {
  166. Ok(ElementReader {
  167. blob_iter: BlobReader::from_path(path)?,
  168. })
  169. }
  170. }