ferric_fred/
shape_file.rs1use serde::{Deserialize, Serialize};
2use serde_json::Value;
3
4#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
17pub struct ShapeFile {
18 #[serde(rename = "type")]
20 pub kind: String,
21
22 pub name: String,
24
25 #[serde(default, skip_serializing_if = "Option::is_none")]
28 pub crs: Option<Value>,
29
30 pub features: Vec<Feature>,
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
37#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
38pub struct Feature {
39 #[serde(rename = "type")]
41 pub kind: String,
42
43 pub properties: Value,
48
49 pub geometry: Geometry,
51}
52
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
57#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
58pub struct Geometry {
59 #[serde(rename = "type")]
61 pub kind: String,
62
63 pub coordinates: Value,
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 const SHAPE_FILE: &str = r#"{
73 "type": "FeatureCollection",
74 "name": "state_bea_region",
75 "crs": {"type": "name", "properties": {"name": "urn:ogc:def:crs:OGC:1.3:CRS84"}},
76 "features": [
77 {
78 "type": "Feature",
79 "properties": {"bea_region": 8, "bea_regi_1": "Far West"},
80 "geometry": {"type": "MultiPolygon", "coordinates": [[[[1485, 2651], [1482, 2635]]]]}
81 }
82 ]
83 }"#;
84
85 #[test]
86 fn parses_feature_collection() {
87 let shapes: ShapeFile = serde_json::from_str(SHAPE_FILE).expect("shape file parses");
88 assert_eq!(shapes.kind, "FeatureCollection");
89 assert_eq!(shapes.name, "state_bea_region");
90 assert_eq!(shapes.features.len(), 1);
91 let feature = &shapes.features[0];
92 assert_eq!(feature.kind, "Feature");
93 assert_eq!(feature.properties["bea_regi_1"], Value::from("Far West"));
94 assert_eq!(feature.geometry.kind, "MultiPolygon");
95 }
96
97 #[test]
98 fn empty_properties_array_parses() {
99 let feature: Feature = serde_json::from_str(
102 r#"{"type":"Feature","properties":[],
103 "geometry":{"type":"MultiLineString","coordinates":[[[-707,5188],[3651,2950]]]}}"#,
104 )
105 .expect("empty-properties feature parses");
106 assert_eq!(feature.properties, Value::Array(vec![]));
107 assert_eq!(feature.geometry.kind, "MultiLineString");
108 }
109
110 #[test]
111 fn round_trips_geometry_verbatim() {
112 let shapes: ShapeFile = serde_json::from_str(SHAPE_FILE).unwrap();
114 let reserialized = serde_json::to_value(&shapes).unwrap();
115 let original: Value = serde_json::from_str(SHAPE_FILE).unwrap();
116 assert_eq!(reserialized, original);
117 }
118}