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 {}