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