1extern crate byteorder;
48pub extern crate dbase;
49
50pub mod header;
51pub mod reader;
52pub mod record;
53pub mod writer;
54
55#[cfg(feature = "geo-traits")]
56mod geo_traits_impl;
57
58use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
59use std::fmt;
60use std::io::{Read, Write};
61
62pub use reader::{read, read_as, read_shapes, read_shapes_as, Reader, ShapeReader};
63pub use record::Multipatch;
64pub use record::{convert_shapes_to_vec_of, HasShapeType, ReadableShape};
65pub use record::{Multipoint, MultipointM, MultipointZ};
66pub use record::{Patch, Shape, NO_DATA};
67pub use record::{Point, PointM, PointZ};
68pub use record::{Polygon, PolygonM, PolygonRing, PolygonZ};
69pub use record::{Polyline, PolylineM, PolylineZ};
70pub use writer::{ShapeWriter, Writer};
71
72extern crate core;
73#[cfg(feature = "geo-types")]
74extern crate geo_types;
75
76#[derive(Debug)]
78pub enum Error {
79 IoError(std::io::Error),
81 InvalidFileCode(i32),
83 InvalidShapeType(i32),
86 InvalidPatchType(i32),
88 MismatchShapeType {
91 requested: ShapeType,
93 actual: ShapeType,
95 },
96 InvalidShapeRecordSize,
97 DbaseError(dbase::Error),
98 MissingDbf,
99 MissingIndexFile,
100}
101
102impl From<std::io::Error> for Error {
103 fn from(error: std::io::Error) -> Error {
104 Error::IoError(error)
105 }
106}
107
108impl From<dbase::Error> for Error {
109 fn from(e: dbase::Error) -> Error {
110 Error::DbaseError(e)
111 }
112}
113
114impl fmt::Display for Error {
115 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
116 match self {
117 Error::IoError(e) => write!(f, "{}", e),
118 Error::InvalidFileCode(code) => write!(
119 f,
120 "The file code ' {} ' is invalid, is this a Shapefile ?",
121 code
122 ),
123 Error::InvalidShapeType(code) => write!(
124 f,
125 "The code ' {} ' does not correspond to any of the ShapeType code defined by ESRI",
126 code
127 ),
128 Error::MismatchShapeType { requested, actual } => write!(
129 f,
130 "The requested type: '{}' does not correspond to the actual shape type: '{}'",
131 requested, actual
132 ),
133 e => write!(f, "{:?}", e),
134 }
135 }
136}
137
138impl std::error::Error for Error {}
139
140#[derive(Debug, PartialEq, Copy, Clone)]
143pub enum ShapeType {
144 NullShape = 0,
145 Point = 1,
146 Polyline = 3,
147 Polygon = 5,
148 Multipoint = 8,
149
150 PointZ = 11,
151 PolylineZ = 13,
152 PolygonZ = 15,
153 MultipointZ = 18,
154
155 PointM = 21,
156 PolylineM = 23,
157 PolygonM = 25,
158 MultipointM = 28,
159
160 Multipatch = 31,
161}
162
163impl ShapeType {
164 pub(crate) fn read_from<T: Read>(source: &mut T) -> Result<ShapeType, Error> {
165 let code = source.read_i32::<LittleEndian>()?;
166 Self::from(code).ok_or_else(|| Error::InvalidShapeType(code))
167 }
168
169 pub(crate) fn write_to<T: Write>(self, dest: &mut T) -> Result<(), std::io::Error> {
170 dest.write_i32::<LittleEndian>(self as i32)?;
171 Ok(())
172 }
173
174 pub fn from(code: i32) -> Option<ShapeType> {
183 match code {
184 0 => Some(ShapeType::NullShape),
185 1 => Some(ShapeType::Point),
186 3 => Some(ShapeType::Polyline),
187 5 => Some(ShapeType::Polygon),
188 8 => Some(ShapeType::Multipoint),
189 11 => Some(ShapeType::PointZ),
190 13 => Some(ShapeType::PolylineZ),
191 15 => Some(ShapeType::PolygonZ),
192 18 => Some(ShapeType::MultipointZ),
193 21 => Some(ShapeType::PointM),
194 23 => Some(ShapeType::PolylineM),
195 25 => Some(ShapeType::PolygonM),
196 28 => Some(ShapeType::MultipointM),
197 31 => Some(ShapeType::Multipatch),
198 _ => None,
199 }
200 }
201
202 pub fn has_z(self) -> bool {
204 matches!(
205 self,
206 ShapeType::PointZ
207 | ShapeType::PolylineZ
208 | ShapeType::PolygonZ
209 | ShapeType::MultipointZ
210 | ShapeType::Multipatch
211 )
212 }
213
214 pub fn has_m(self) -> bool {
216 matches!(
217 self,
218 ShapeType::PointZ
219 | ShapeType::PolylineZ
220 | ShapeType::PolygonZ
221 | ShapeType::MultipointZ
222 | ShapeType::PointM
223 | ShapeType::PolylineM
224 | ShapeType::PolygonM
225 | ShapeType::MultipointM
226 )
227 }
228
229 pub fn is_multipart(self) -> bool {
231 !matches!(
232 self,
233 ShapeType::Point
234 | ShapeType::PointM
235 | ShapeType::PointZ
236 | ShapeType::Multipoint
237 | ShapeType::MultipointM
238 | ShapeType::MultipointZ
239 )
240 }
241}
242
243impl fmt::Display for ShapeType {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
245 match self {
246 ShapeType::NullShape => write!(f, "NullShape"),
247 ShapeType::Point => write!(f, "Point"),
248 ShapeType::Polyline => write!(f, "Polyline"),
249 ShapeType::Polygon => write!(f, "Polygon"),
250 ShapeType::Multipoint => write!(f, "Multipoint"),
251 ShapeType::PointZ => write!(f, "PointZ"),
252 ShapeType::PolylineZ => write!(f, "PolylineZ"),
253 ShapeType::PolygonZ => write!(f, "PolygonZ"),
254 ShapeType::MultipointZ => write!(f, "MultipointZ"),
255 ShapeType::PointM => write!(f, "PointM"),
256 ShapeType::PolylineM => write!(f, "PolylineM"),
257 ShapeType::PolygonM => write!(f, "PolygonM"),
258 ShapeType::MultipointM => write!(f, "MultipointM"),
259 ShapeType::Multipatch => write!(f, "Multipatch"),
260 }
261 }
262}