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

reader.rs 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. //! High level reader interface
  2. use blob::{BlobDecode, BlobReader};
  3. use elements::Element;
  4. use error::Result;
  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. Ok(block.elements()
  123. .map(|e| map_op(e))
  124. .fold(identity(), |a, b| reduce_op(a, b)))
  125. },
  126. Err(e) => Err(e),
  127. }
  128. }).reduce(|| Ok(identity()), |a, b| {
  129. match (a, b) {
  130. (Ok(x), Ok(y)) => Ok(reduce_op(x, y)),
  131. (x, y) => x.and(y),
  132. }
  133. })
  134. }
  135. }
  136. impl ElementReader<BufReader<File>> {
  137. /// Tries to open the file at the given path and constructs an `ElementReader` from this.
  138. ///
  139. /// # Errors
  140. /// Returns the same errors that `std::fs::File::open` returns.
  141. ///
  142. /// # Example
  143. /// ```
  144. /// use osmpbf::*;
  145. ///
  146. /// # fn foo() -> Result<()> {
  147. /// let reader = ElementReader::from_path("tests/test.osm.pbf")?;
  148. /// # Ok(())
  149. /// # }
  150. /// ```
  151. pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self>
  152. {
  153. Ok(ElementReader {
  154. blob_iter: BlobReader::from_path(path)?,
  155. })
  156. }
  157. }