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

reader.rs 6.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. //! High level reader interface
  2. use blob::{BlobDecode, BlobReader};
  3. use dense::DenseNode;
  4. use elements::{Node, Way, Relation};
  5. use errors::*;
  6. use rayon::prelude::*;
  7. use std::fs::File;
  8. use std::io::{BufReader, Read};
  9. use std::path::Path;
  10. /// A reader for PBF files that gives access to the stored elements: nodes, ways and relations.
  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. for group in block.groups() {
  70. for node in group.nodes() {
  71. f(Element::Node(node))
  72. }
  73. for dnode in group.dense_nodes() {
  74. f(Element::DenseNode(dnode))
  75. }
  76. for way in group.ways() {
  77. f(Element::Way(way));
  78. }
  79. for relation in group.relations() {
  80. f(Element::Relation(relation));
  81. }
  82. }
  83. },
  84. Err(e) => return Err(e),
  85. }
  86. }
  87. Ok(())
  88. }
  89. /// Parallel map/reduce. Decodes the PBF structure in parallel, calls the closure `map_op` on
  90. /// each element and then reduces the number of results to one item with the closure
  91. /// `reduce_op`. Similarly to the `init` argument in the `fold` method on iterators, the
  92. /// `identity` closure should produce an identity value that is inserted into `reduce_op` when
  93. /// necessary. The number of times that this identity value is inserted should not alter the
  94. /// result.
  95. ///
  96. /// # Errors
  97. /// Returns the first Error encountered while parsing the PBF structure.
  98. ///
  99. /// # Example
  100. /// ```
  101. /// use osmpbf::*;
  102. ///
  103. /// # fn foo() -> Result<()> {
  104. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  105. ///
  106. /// // Count the ways
  107. /// let ways = reader.par_map_reduce(
  108. /// |element| {
  109. /// match element {
  110. /// Element::Way(_) => 1,
  111. /// _ => 0,
  112. /// }
  113. /// },
  114. /// || 0_u64, // Zero is the identity value for addition
  115. /// |a, b| a + b // Sum the partial results
  116. /// )?;
  117. ///
  118. /// println!("Number of ways: {}", ways);
  119. /// # Ok(())
  120. /// # }
  121. /// ```
  122. pub fn par_map_reduce<MP, RD, ID, T>(self, map_op: MP, identity: ID, reduce_op: RD) -> Result<T>
  123. where MP: for<'a> Fn(Element<'a>) -> T + Sync + Send,
  124. RD: Fn(T, T) -> T + Sync + Send,
  125. ID: Fn() -> T + Sync + Send,
  126. T: Send,
  127. {
  128. let blobs = self.blob_iter.collect::<Result<Vec<_>>>()?;
  129. blobs.into_par_iter().map(|blob| {
  130. match blob.decode() {
  131. Ok(BlobDecode::OsmHeader(_)) | Ok(BlobDecode::Unknown(_)) => {
  132. Ok(identity())
  133. },
  134. Ok(BlobDecode::OsmData(block)) => {
  135. let dnodes = block.groups()
  136. .flat_map(|g| g.dense_nodes())
  137. .map(|dn| map_op(Element::DenseNode(dn)));
  138. let nodes = block.groups()
  139. .flat_map(|g| g.nodes())
  140. .map(|n| map_op(Element::Node(n)));
  141. let ways = block.groups()
  142. .flat_map(|g| g.ways())
  143. .map(|w| map_op(Element::Way(w)));
  144. let rels = block.groups()
  145. .flat_map(|g| g.relations())
  146. .map(|r| map_op(Element::Relation(r)));
  147. Ok(dnodes.chain(nodes)
  148. .chain(ways)
  149. .chain(rels)
  150. .fold(identity(), |a, b| reduce_op(a, b)))
  151. },
  152. Err(e) => Err(e),
  153. }
  154. }).reduce(|| Ok(identity()), |a, b| {
  155. match (a, b) {
  156. (Ok(x), Ok(y)) => Ok(reduce_op(x, y)),
  157. (x, y) => x.and(y),
  158. }
  159. })
  160. }
  161. }
  162. impl ElementReader<BufReader<File>> {
  163. /// Tries to open the file at the given path and constructs an `ElementReader` from this.
  164. ///
  165. /// # Errors
  166. /// Returns the same errors that `std::fs::File::open` returns.
  167. ///
  168. /// # Example
  169. /// ```
  170. /// use osmpbf::*;
  171. ///
  172. /// # fn foo() -> Result<()> {
  173. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  174. /// # Ok(())
  175. /// # }
  176. /// ```
  177. pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self>
  178. {
  179. let f = File::open(path)?;
  180. let reader = BufReader::new(f);
  181. Ok(ElementReader {
  182. blob_iter: BlobReader::new(reader),
  183. })
  184. }
  185. }
  186. /// An enum with the OSM core elements: nodes, ways and relations.
  187. pub enum Element<'a> {
  188. /// A node. Also, see `DenseNode`.
  189. Node(Node<'a>),
  190. /// Just like `Node`, but with a different representation in memory. This distinction is
  191. /// usually not important but is not abstracted away to avoid copying. So, if you want to match
  192. /// `Node`, you also likely want to match `DenseNode`.
  193. DenseNode(DenseNode<'a>),
  194. /// A way.
  195. Way(Way<'a>),
  196. /// A relation.
  197. Relation(Relation<'a>),
  198. }