shapefile/reader.rs
1//! Reader module, contains the definitions of the types that a user should use to read a file
2//!
3//! # Reader
4//!
5//! The [Reader] is the struct that actually reads the different files
6//! that make up a _shapefile_.
7//!
8//! ## Examples
9//!
10//! When reading from a file:
11//!
12//! Creates a reader from a path, then iterate over its `Shapes`, reading one shape each iteration
13//! ```
14//! # fn main() -> Result<(), shapefile::Error> {
15//! let mut reader = shapefile::Reader::from_path("tests/data/multipatch.shp")?;
16//! for shape_record in reader.iter_shapes_and_records() {
17//! let (shape, record) = shape_record?;
18//! println!("{}", shape);
19//! }
20//! # Ok(())
21//! # }
22//! ```
23//!
24//! # ShapeReader
25//!
26//! If you only care about the geometries stored in the _.shp_ file, whether or not the _.dbf_ file
27//! actually exists, you can use the [ShapeReader].
28//!
29//! # Extra
30//!
31//! If you know beforehand the exact type that the .shp file is made of,
32//! you can use the different `*_as::<S>()` methods.:
33//! - [Reader::read_as] To read all the shapes and records as the specified types using a Reader
34//! - [Reader::iter_shapes_and_records_as] To iterate over both the shapes and records of the Reader
35//!
36//! - [ShapeReader::read_as] To read all the shapes (only) as the specified type using ShapeReader
37//! - [ShapeReader::iter_shapes_as] To iterate over the shapes as shapes
38//! of the specified type using ShapeReader
39//!
40//!
41//! Otherwise use the functions that return [Shapes](../record/enum.Shape.html) and do a `match`
42//!
43//! - [Reader::read]
44//! - [Reader::iter_shapes_and_records]
45//! - [ShapeReader::read]
46//! - [ShapeReader::iter_shapes]
47//!
48//! ## One liners
49//!
50//! Some 'one liner' functions are provided to read the content
51//! of a shapefile with one line of code
52//!
53//! - [read]
54//! - [read_as]
55//! - [read_shapes]
56//! - [read_shapes_as]
57
58use std::fs::File;
59use std::io::{BufReader, Read, Seek, SeekFrom, Write};
60use std::path::Path;
61
62use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
63
64use crate::header;
65use crate::record;
66use crate::record::ReadableShape;
67use crate::{Error, Shape};
68
69const INDEX_RECORD_SIZE: usize = 2 * std::mem::size_of::<i32>();
70
71#[derive(Copy, Clone)]
72pub(crate) struct ShapeIndex {
73 pub offset: i32,
74 pub record_size: i32,
75}
76
77impl ShapeIndex {
78 pub(crate) fn write_to<W: Write>(self, dest: &mut W) -> std::io::Result<()> {
79 dest.write_i32::<BigEndian>(self.offset)?;
80 dest.write_i32::<BigEndian>(self.record_size)?;
81 Ok(())
82 }
83}
84
85/// Read the content of a .shx file
86fn read_index_file<T: Read>(mut source: T) -> Result<Vec<ShapeIndex>, Error> {
87 let header = header::Header::read_from(&mut source)?;
88
89 let num_shapes = ((header.file_length * 2) - header::HEADER_SIZE) / INDEX_RECORD_SIZE as i32;
90 let mut shapes_index = Vec::<ShapeIndex>::with_capacity(num_shapes as usize);
91 for _ in 0..num_shapes {
92 let offset = source.read_i32::<BigEndian>()?;
93 let record_size = source.read_i32::<BigEndian>()?;
94 shapes_index.push(ShapeIndex {
95 offset,
96 record_size,
97 });
98 }
99 Ok(shapes_index)
100}
101
102/// Reads and returns one shape and its header from the source
103fn read_one_shape_as<T: Read, S: ReadableShape>(
104 mut source: &mut T,
105) -> Result<(record::RecordHeader, S), Error> {
106 let hdr = record::RecordHeader::read_from(&mut source)?;
107 let record_size = hdr.record_size * 2;
108 let shape = S::read_from(&mut source, record_size)?;
109 Ok((hdr, shape))
110}
111
112/// Struct that handle iteration over the shapes of a .shp file
113pub struct ShapeIterator<'a, T: Read, S: ReadableShape> {
114 _shape: std::marker::PhantomData<S>,
115 // From where we read the shapes
116 source: &'a mut T,
117 // Current position in bytes in the source.
118 current_pos: usize,
119 // How many bytes the header said there are in
120 // the file.
121 file_length: usize,
122 // Iterator over the shape indices, used to seek
123 // to the start of a shape when reading
124 shapes_indices: Option<std::slice::Iter<'a, ShapeIndex>>,
125}
126
127impl<T: Read + Seek, S: ReadableShape> Iterator for ShapeIterator<'_, T, S> {
128 type Item = Result<S, crate::Error>;
129
130 fn next(&mut self) -> Option<Self::Item> {
131 if self.current_pos >= self.file_length {
132 None
133 } else {
134 if let Some(ref mut shapes_indices) = self.shapes_indices {
135 // Its 'safer' to seek to the shape offset when we have the `shx` file
136 // as some shapes may not be stored sequentially and may contain 'garbage'
137 // bytes between them
138 let start_pos = shapes_indices.next()?.offset * 2;
139 if start_pos != self.current_pos as i32 {
140 if let Err(err) = self.source.seek(SeekFrom::Start(start_pos as u64)) {
141 return Some(Err(err.into()));
142 }
143 self.current_pos = start_pos as usize;
144 }
145 }
146 let (hdr, shape) = match read_one_shape_as::<T, S>(self.source) {
147 Err(e) => return Some(Err(e)),
148 Ok(hdr_and_shape) => hdr_and_shape,
149 };
150 self.current_pos += record::RecordHeader::SIZE;
151 self.current_pos += hdr.record_size as usize * 2;
152 Some(Ok(shape))
153 }
154 }
155
156 fn size_hint(&self) -> (usize, Option<usize>) {
157 self.shapes_indices
158 .as_ref()
159 .map(|s| s.size_hint())
160 .unwrap_or((0, None))
161 }
162}
163
164pub struct ShapeRecordIterator<
165 'a,
166 T: Read + Seek,
167 D: Read + Seek,
168 S: ReadableShape,
169 R: dbase::ReadableRecord,
170> {
171 shape_iter: ShapeIterator<'a, T, S>,
172 record_iter: dbase::RecordIterator<'a, D, R>,
173}
174
175impl<T: Read + Seek, D: Read + Seek, S: ReadableShape, R: dbase::ReadableRecord> Iterator
176 for ShapeRecordIterator<'_, T, D, S, R>
177{
178 type Item = Result<(S, R), Error>;
179
180 fn next(&mut self) -> Option<Self::Item> {
181 let shape = match self.shape_iter.next()? {
182 Err(e) => return Some(Err(e)),
183 Ok(shp) => shp,
184 };
185
186 let record = match self.record_iter.next()? {
187 Err(e) => return Some(Err(Error::DbaseError(e))),
188 Ok(rcd) => rcd,
189 };
190
191 Some(Ok((shape, record)))
192 }
193}
194
195/// This reader only reads the `.shp` and optionally the (`.shx`) files
196/// of a shapefile.
197pub struct ShapeReader<T> {
198 source: T,
199 header: header::Header,
200 shapes_index: Option<Vec<ShapeIndex>>,
201}
202
203impl<T: Read> ShapeReader<T> {
204 /// Creates a new ShapeReader from a source that implements the `Read` trait
205 ///
206 /// The Shapefile header is read upon creation (but no reading of the Shapes is done)
207 ///
208 /// # Errors
209 ///
210 /// Will forward any `std::io::Error`
211 ///
212 /// Will also return an error if the data is not a shapefile (Wrong file code)
213 ///
214 /// Will also return an error if the shapetype read from the input source is invalid
215 ///
216 /// # Example
217 ///
218 /// ```
219 /// # fn main() -> Result<(), shapefile::Error> {
220 /// use std::fs::File;
221 /// let file = File::open("tests/data/line.shp")?;
222 /// let reader = shapefile::ShapeReader::new(file)?;
223 /// # Ok(())
224 /// # }
225 /// ```
226 pub fn new(mut source: T) -> Result<Self, Error> {
227 let header = header::Header::read_from(&mut source)?;
228
229 Ok(Self {
230 source,
231 header,
232 shapes_index: None,
233 })
234 }
235
236 /// Creates a new ShapeReader using 2 sources, one for the _.shp_
237 /// the other for the _.shx_
238 ///
239 /// The _.shp_ header is read upon creation
240 /// and the whole _.shx_ file is read upon creation.
241 ///
242 /// # Example
243 /// ```no_run
244 /// # fn main() -> Result<(), shapefile::Error> {
245 /// use std::fs::File;
246 /// let shp_file = File::open("cities.shp")?;
247 /// let shx_file = File::open("cities.shx:")?;
248 /// let reader = shapefile::ShapeReader::with_shx(shp_file, shx_file)?;
249 /// # Ok(())
250 /// # }
251 /// ```
252 pub fn with_shx<ShxSource>(mut source: T, shx_source: ShxSource) -> Result<Self, Error>
253 where
254 ShxSource: Read,
255 {
256 let shapes_index = Some(read_index_file(shx_source)?);
257 let header = header::Header::read_from(&mut source)?;
258
259 Ok(Self {
260 source,
261 header,
262 shapes_index,
263 })
264 }
265
266 /// Returns a non-mutable reference to the header read
267 ///
268 /// # Examples
269 ///
270 /// ```
271 /// # fn main() -> Result<(), shapefile::Error> {
272 /// let reader = shapefile::ShapeReader::from_path("tests/data/pointz.shp")?;
273 /// let header = reader.header();
274 /// assert_eq!(header.shape_type, shapefile::ShapeType::PointZ);
275 /// # Ok(())
276 /// # }
277 /// ```
278 pub fn header(&self) -> &header::Header {
279 &self.header
280 }
281}
282
283impl<T: Read + Seek> ShapeReader<T> {
284 /// Reads all the shape as shape of a certain type.
285 ///
286 /// To be used if you know in advance which shape type the file contains.
287 ///
288 /// # Errors
289 /// The function has an additional error that is returned if the shape type you asked to be
290 /// read does not match the actual shape type in the file.
291 ///
292 /// # Examples
293 ///
294 /// ```
295 /// # fn main() -> Result<(), shapefile::Error> {
296 /// use shapefile::ShapeReader;
297 /// let mut reader = ShapeReader::from_path("tests/data/linem.shp")?;
298 /// let polylines_m = reader.read_as::<shapefile::PolylineM>(); // we ask for the correct type
299 /// assert_eq!(polylines_m.is_ok(), true);
300 /// # Ok(())
301 /// # }
302 /// ```
303 ///
304 /// ```
305 /// # fn main() -> Result<(), shapefile::Error> {
306 /// use shapefile::ShapeReader;
307 /// let mut reader = ShapeReader::from_path("tests/data/linem.shp")?;
308 /// let polylines = reader.read_as::<shapefile::Polyline>(); // we ask for the wrong type
309 /// assert_eq!(polylines.is_err(), true);
310 /// # Ok(())
311 /// # }
312 /// ```
313 pub fn read_as<S: ReadableShape>(mut self) -> Result<Vec<S>, Error> {
314 self.iter_shapes_as::<S>().collect()
315 }
316
317 /// Reads all the shapes and returns them
318 ///
319 /// # Examples
320 /// ```
321 /// # fn main() -> Result<(), shapefile::Error> {
322 /// let mut reader = shapefile::ShapeReader::from_path("tests/data/multipoint.shp")?;
323 /// let shapes = reader.read()?;
324 /// for shape in shapes {
325 /// match shape {
326 /// shapefile::Shape::Multipoint(pts) => println!(" Yay Multipoints: {}", pts),
327 /// _ => panic!("ups, not multipoints"),
328 /// }
329 /// }
330 /// # Ok(())
331 /// # }
332 /// ```
333 ///
334 pub fn read(mut self) -> Result<Vec<Shape>, Error> {
335 self.iter_shapes_as::<Shape>().collect()
336 }
337
338 /// Returns an iterator that tries to read the shapes as the specified type
339 /// Will return an error of the type `S` does not match the actual type in the file
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// # fn main() -> Result<(), shapefile::Error> {
345 /// let mut reader = shapefile::ShapeReader::from_path("tests/data/multipoint.shp")?;
346 /// for multipoints in reader.iter_shapes_as::<shapefile::Multipoint>() {
347 /// let points = multipoints?;
348 /// println!("{}", points);
349 /// }
350 /// # Ok(())
351 /// # }
352 /// ```
353 pub fn iter_shapes_as<S: ReadableShape>(&mut self) -> ShapeIterator<'_, T, S> {
354 ShapeIterator {
355 _shape: std::marker::PhantomData,
356 source: &mut self.source,
357 current_pos: header::HEADER_SIZE as usize,
358 file_length: (self.header.file_length as usize) * 2,
359 shapes_indices: self.shapes_index.as_ref().map(|s| s.iter()),
360 }
361 }
362
363 /// Returns an iterator that to reads the shapes wraps them in the enum [Shape](enum.Shape.html)
364 /// You do not need to call this method and can iterate over the `Reader` directly
365 ///
366 /// # Examples
367 ///
368 /// ```
369 /// # fn main() -> Result<(), shapefile::Error> {
370 /// let mut reader = shapefile::ShapeReader::from_path("tests/data/multipoint.shp")?;
371 /// for shape in reader.iter_shapes() {
372 /// match shape? {
373 /// shapefile::Shape::Multipatch(shp) => println!("Multipoint!"),
374 /// _ => println!("Other type of shape"),
375 /// }
376 /// }
377 /// # Ok(())
378 /// # }
379 /// ```
380 ///
381 /// ```
382 /// # fn main() -> Result<(), shapefile::Error> {
383 /// let mut reader = shapefile::ShapeReader::from_path("tests/data/multipoint.shp")?;
384 /// for shape in reader.iter_shapes() {
385 /// match shape? {
386 /// shapefile::Shape::Multipatch(shp) => println!("Multipoint!"),
387 /// _ => println!("Other type of shape"),
388 /// }
389 /// }
390 /// # Ok(())
391 /// # }
392 /// ```
393 pub fn iter_shapes(&mut self) -> ShapeIterator<'_, T, Shape> {
394 self.iter_shapes_as::<Shape>()
395 }
396
397 /// Reads the `n`th shape of the shapefile
398 ///
399 /// # Important
400 ///
401 /// Even though in shapefiles, shapes are indexed starting from '1'.
402 /// this method expects indexes starting from 0.
403 ///
404 /// # Returns
405 ///
406 /// `None` if the index is out of range
407 ///
408 /// # Errors
409 ///
410 /// This method will return an `Error::MissingIndexFile` if you use it
411 /// but no *.shx* was found when opening the shapefile.
412 pub fn read_nth_shape_as<S: ReadableShape>(
413 &mut self,
414 index: usize,
415 ) -> Option<Result<S, Error>> {
416 if let Some(ref shapes_index) = self.shapes_index {
417 if index >= shapes_index.len() {
418 return None;
419 }
420
421 if let Err(e) = self.seek(index) {
422 return Some(Err(e));
423 }
424
425 let (_, shape) = match read_one_shape_as::<T, S>(&mut self.source) {
426 Err(e) => return Some(Err(e)),
427 Ok(hdr_and_shape) => hdr_and_shape,
428 };
429
430 if let Err(e) = self
431 .source
432 .seek(SeekFrom::Start(header::HEADER_SIZE as u64))
433 {
434 return Some(Err(Error::IoError(e)));
435 }
436 Some(Ok(shape))
437 } else {
438 Some(Err(Error::MissingIndexFile))
439 }
440 }
441
442 /// Reads the `n`th shape of the shapefile
443 pub fn read_nth_shape(&mut self, index: usize) -> Option<Result<Shape, Error>> {
444 self.read_nth_shape_as::<Shape>(index)
445 }
446
447 /// Seek to the start of the shape at `index`
448 ///
449 /// # Error
450 ///
451 /// Returns [Error::MissingIndexFile] if the _shx_ file
452 /// was not found by [ShapeReader::from_path] or the reader
453 /// was not constructed with [ShapeReader::with_shx]
454 pub fn seek(&mut self, index: usize) -> Result<(), Error> {
455 if let Some(ref shapes_index) = self.shapes_index {
456 let offset = shapes_index
457 .get(index)
458 .map(|shape_idx| (shape_idx.offset * 2) as u64);
459
460 match offset {
461 Some(n) => self.source.seek(SeekFrom::Start(n)),
462 None => self.source.seek(SeekFrom::End(0)),
463 }?;
464 Ok(())
465 } else {
466 Err(Error::MissingIndexFile)
467 }
468 }
469
470 /// Returns the number of shapes in the shapefile
471 ///
472 /// # Error
473 ///
474 /// Returns [Error::MissingIndexFile] if the _shx_ file
475 /// was not found by [ShapeReader::from_path] or the reader
476 /// was not constructed with [ShapeReader::with_shx]
477 ///
478 /// # Example
479 ///
480 /// ```
481 /// let reader = shapefile::ShapeReader::from_path("tests/data/point.shp").unwrap();
482 /// // point.shp has a .shx file next to it, so we can read the count data
483 /// assert_eq!(1, reader.shape_count().unwrap());
484 ///
485 /// let reader = shapefile::ShapeReader::from_path("tests/data/pointm.shp").unwrap();
486 /// // There is no pointm.shx, so the shape_count() method returns error
487 /// assert!(reader.shape_count().is_err(), "Should return error if no index file");
488 /// ```
489 pub fn shape_count(&self) -> Result<usize, Error> {
490 if let Some(ref shapes_index) = self.shapes_index {
491 Ok(shapes_index.len())
492 } else {
493 Err(Error::MissingIndexFile)
494 }
495 }
496}
497
498impl ShapeReader<BufReader<File>> {
499 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
500 let shape_path = path.as_ref().to_path_buf();
501 let shx_path = shape_path.with_extension("shx");
502
503 let source = BufReader::new(File::open(shape_path)?);
504
505 if shx_path.exists() {
506 let index_source = BufReader::new(File::open(shx_path)?);
507 Self::with_shx(source, index_source)
508 } else {
509 Self::new(source)
510 }
511 }
512}
513
514/// Reader that reads a _shapefile_.
515///
516/// The recommended way to create a _Reader_ is by using its
517/// [Reader::from_path] associated function as it
518/// will take care of opening the _.shx_ and _.dbf_ files corresponding to the _.shp_
519/// and return an error in case some mandatory files are missing.
520///
521///
522/// If you want to read a shapefile that is not stored in a file
523/// (e.g the shp data is in a buffer), you will have to construct
524/// the *Reader* "by hand" with its [Reader::new] associated function.
525pub struct Reader<T: Read + Seek, D: Read + Seek> {
526 shape_reader: ShapeReader<T>,
527 dbase_reader: dbase::Reader<D>,
528}
529
530impl<T: Read + Seek, D: Read + Seek> Reader<T, D> {
531 /// Creates a new Reader from both a ShapeReader (.shp, .shx) and dbase::Reader (.dbf)
532 pub fn new(shape_reader: ShapeReader<T>, dbase_reader: dbase::Reader<D>) -> Self {
533 Self {
534 shape_reader,
535 dbase_reader,
536 }
537 }
538
539 /// Returns the header of the .shp file
540 pub fn header(&self) -> &header::Header {
541 self.shape_reader.header()
542 }
543
544 pub fn iter_shapes_and_records_as<S: ReadableShape, R: dbase::ReadableRecord>(
545 &mut self,
546 ) -> ShapeRecordIterator<'_, T, D, S, R> {
547 ShapeRecordIterator {
548 shape_iter: self.shape_reader.iter_shapes_as::<S>(),
549 record_iter: self.dbase_reader.iter_records_as::<R>(),
550 }
551 }
552
553 /// Returns an iterator that returns both the shape and the record
554 ///
555 /// # Example
556 ///
557 /// ```
558 /// # fn main() -> Result<(), shapefile::Error> {
559 /// let mut reader = shapefile::Reader::from_path("tests/data/multipatch.shp")?;
560 /// for shape_record in reader.iter_shapes_and_records() {
561 /// let (shape, record) = shape_record?;
562 /// println!("Geometry: {}, Properties {:?}", shape, record);
563 /// }
564 /// # Ok(())
565 /// # }
566 /// ```
567 pub fn iter_shapes_and_records(
568 &mut self,
569 ) -> ShapeRecordIterator<'_, T, D, Shape, dbase::Record> {
570 self.iter_shapes_and_records_as::<Shape, dbase::Record>()
571 }
572
573 pub fn read_as<S: ReadableShape, R: dbase::ReadableRecord>(
574 &mut self,
575 ) -> Result<Vec<(S, R)>, Error> {
576 self.iter_shapes_and_records_as::<S, R>().collect()
577 }
578
579 /// Read all the shape and record and returns them in a [Vec]
580 ///
581 /// # Example
582 ///
583 /// ```
584 /// # fn main() -> Result<(), shapefile::Error> {
585 /// let mut reader = shapefile::Reader::from_path("tests/data/multipatch.shp")?;
586 /// let data = reader.read()?;
587 /// # Ok(())
588 /// # }
589 /// ```
590 pub fn read(&mut self) -> Result<Vec<(Shape, dbase::Record)>, Error> {
591 self.read_as::<Shape, dbase::Record>()
592 }
593
594 /// Seeks to the start of the shape at `index`
595 pub fn seek(&mut self, index: usize) -> Result<(), Error> {
596 self.shape_reader.seek(index)?;
597 self.dbase_reader.seek(index)?;
598 Ok(())
599 }
600
601 /// Returns the number of shapes in the shapefile
602 ///
603 /// See [ShapeReader::shape_count]
604 pub fn shape_count(&self) -> Result<usize, Error> {
605 self.shape_reader.shape_count()
606 }
607
608 /// Consumes the self and returns the dbase table info
609 /// which can be given to [TableWriterBuild](dbase::TableWriterBuilder) or
610 /// [crate::Writer::from_path_with_info] to create a shapefile where the .dbf file has the
611 /// same structure as the .dbf read by this reader
612 pub fn into_table_info(self) -> dbase::TableInfo {
613 self.dbase_reader.into_table_info()
614 }
615}
616
617impl Reader<BufReader<File>, BufReader<File>> {
618 /// Creates a reader from a path the .shp file
619 ///
620 /// Will attempt to read both the `.shx` and `.dbf` associated with the file,
621 ///
622 /// If the `.shx` is not found, no error will be returned,
623 /// however [seek] will fail is used.
624 ///
625 /// If the `.dbf` is not found [Error::MissingDbf] will be return as the error.
626 ///
627 /// [seek]: ShapeReader::seek
628 ///
629 /// # Examples
630 ///
631 /// ```
632 /// use std::path::Path;
633 /// # fn main() -> Result<(), shapefile::Error> {
634 /// assert_eq!(Path::new("tests/data/linem.dbf").exists(), false);
635 /// assert_eq!(Path::new("tests/data/linem.shx").exists(), false);
636 ///
637 /// // .dbf file not found, the reader can't be created
638 /// let mut reader = shapefile::Reader::from_path("tests/data/linem.shp");
639 /// assert_eq!(reader.is_err(), true);
640 ///
641 /// assert_eq!(Path::new("tests/data/multipatch.dbf").exists(), true);
642 ///
643 /// // The dbf file exists, the reader can be created
644 /// let mut reader = shapefile::Reader::from_path("tests/data/multipatch.shp");
645 /// assert_eq!(reader.is_err(), false);
646 /// # Ok(())
647 /// # }
648 /// ```
649 pub fn from_path<P: AsRef<Path>>(path: P) -> Result<Self, Error> {
650 let shape_path = path.as_ref().to_path_buf();
651 let dbf_path = shape_path.with_extension("dbf");
652
653 if dbf_path.exists() {
654 let shape_reader = ShapeReader::from_path(path)?;
655 let dbf_source = BufReader::new(File::open(dbf_path)?);
656 let dbf_reader = dbase::Reader::new(dbf_source)?;
657 Ok(Self {
658 shape_reader,
659 dbase_reader: dbf_reader,
660 })
661 } else {
662 Err(Error::MissingDbf)
663 }
664 }
665}
666
667pub fn read<T: AsRef<Path>>(path: T) -> Result<Vec<(Shape, dbase::Record)>, Error> {
668 read_as::<T, Shape, dbase::Record>(path)
669}
670
671pub fn read_as<T: AsRef<Path>, S: ReadableShape, R: dbase::ReadableRecord>(
672 path: T,
673) -> Result<Vec<(S, R)>, Error> {
674 Reader::from_path(path).and_then(|mut rdr| rdr.read_as::<S, R>())
675}
676
677/// Function to read all the Shapes in a file as a certain type
678///
679/// It does not open the .dbf file.
680///
681/// Fails and return `Err(Error:MismatchShapeType)`
682///
683/// # Examples
684///
685/// ```
686/// let polylines = shapefile::read_shapes_as::<_, shapefile::PolylineZ>("tests/data/polygon.shp");
687/// assert_eq!(polylines.is_err(), true);
688///
689/// let polygons = shapefile::read_shapes_as::<_, shapefile::Polygon>("tests/data/polygon.shp");
690/// assert_eq!(polygons.is_ok(), true);
691/// ```
692///
693/// If the reading is successful, the returned `Vec<S:ReadShape>>`is a vector of actual structs
694/// Useful if you know in at compile time which kind of shape you expect the file to have
695pub fn read_shapes_as<T: AsRef<Path>, S: ReadableShape>(path: T) -> Result<Vec<S>, Error> {
696 ShapeReader::from_path(path).and_then(|rdr| rdr.read_as::<S>())
697}
698
699/// Function to read all the Shapes in a file.
700///
701/// Returns a `Vec<Shape>` which means that you will have to `match`
702/// the individual [Shape](enum.Shape.html) contained inside the `Vec` to get the actual `struct`
703///
704/// Useful if you don't know in advance (at compile time) which kind of
705/// shape the file contains
706///
707/// # Examples
708///
709/// ```
710/// # fn main() -> Result<(), shapefile::Error> {
711/// let shapes = shapefile::read_shapes("tests/data/multipatch.shp")?;
712/// assert_eq!(shapes.len(), 1);
713/// # Ok(())
714/// # }
715/// ```
716pub fn read_shapes<T: AsRef<Path>>(path: T) -> Result<Vec<Shape>, Error> {
717 read_shapes_as::<T, Shape>(path)
718}
719
720#[cfg(test)]
721mod tests {}