geojson/
util.rs

1// Copyright 2015 The GeoRust Developers
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//  http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use crate::errors::{Error, Result};
16use crate::{feature, Bbox, Feature, Geometry, Position, Value};
17use crate::{JsonObject, JsonValue};
18
19pub fn expect_type(value: &mut JsonObject) -> Result<String> {
20    let prop = expect_property(value, "type")?;
21    expect_string(prop)
22}
23
24pub fn expect_string(value: JsonValue) -> Result<String> {
25    match value {
26        JsonValue::String(s) => Ok(s),
27        _ => Err(Error::ExpectedStringValue(value)),
28    }
29}
30
31pub fn expect_f64(value: &JsonValue) -> Result<f64> {
32    match value.as_f64() {
33        Some(v) => Ok(v),
34        None => Err(Error::ExpectedF64Value),
35    }
36}
37
38pub fn expect_array(value: &JsonValue) -> Result<&Vec<JsonValue>> {
39    match value.as_array() {
40        Some(v) => Ok(v),
41        None => Err(Error::ExpectedArrayValue("None".to_string())),
42    }
43}
44
45fn expect_property(obj: &mut JsonObject, name: &'static str) -> Result<JsonValue> {
46    match obj.remove(name) {
47        Some(v) => Ok(v),
48        None => Err(Error::ExpectedProperty(name.to_string())),
49    }
50}
51
52fn expect_owned_array(value: JsonValue) -> Result<Vec<JsonValue>> {
53    match value {
54        JsonValue::Array(v) => Ok(v),
55        _ => match value {
56            // it can never be Array, but that's exhaustive matches for you
57            JsonValue::Array(_) => Err(Error::ExpectedArrayValue("Array".to_string())),
58            JsonValue::Null => Err(Error::ExpectedArrayValue("Null".to_string())),
59            JsonValue::Bool(_) => Err(Error::ExpectedArrayValue("Bool".to_string())),
60            JsonValue::Number(_) => Err(Error::ExpectedArrayValue("Number".to_string())),
61            JsonValue::String(_) => Err(Error::ExpectedArrayValue("String".to_string())),
62            JsonValue::Object(_) => Err(Error::ExpectedArrayValue("Object".to_string())),
63        },
64    }
65}
66
67pub(crate) fn expect_owned_object(value: JsonValue) -> Result<JsonObject> {
68    match value {
69        JsonValue::Object(o) => Ok(o),
70        _ => Err(Error::ExpectedObjectValue(value)),
71    }
72}
73
74pub fn get_coords_value(object: &mut JsonObject) -> Result<JsonValue> {
75    expect_property(object, "coordinates")
76}
77
78/// Used by FeatureCollection, Feature, Geometry
79pub fn get_bbox(object: &mut JsonObject) -> Result<Option<Bbox>> {
80    let bbox_json = match object.remove("bbox") {
81        Some(JsonValue::Null) | None => return Ok(None),
82        Some(b) => b,
83    };
84    let bbox_array = match bbox_json {
85        JsonValue::Array(a) => a,
86        _ => return Err(Error::BboxExpectedArray(bbox_json)),
87    };
88    let bbox = bbox_array
89        .into_iter()
90        .map(|i| i.as_f64().ok_or(Error::BboxExpectedNumericValues(i)))
91        .collect::<Result<Vec<_>>>()?;
92    Ok(Some(bbox))
93}
94
95/// Used by FeatureCollection, Feature, Geometry
96pub fn get_foreign_members(object: JsonObject) -> Result<Option<JsonObject>> {
97    if object.is_empty() {
98        Ok(None)
99    } else {
100        Ok(Some(object))
101    }
102}
103
104/// Used by Feature
105pub fn get_properties(object: &mut JsonObject) -> Result<Option<JsonObject>> {
106    let properties = expect_property(object, "properties");
107    match properties {
108        Ok(JsonValue::Object(x)) => Ok(Some(x)),
109        Ok(JsonValue::Null) | Err(Error::ExpectedProperty(_)) => Ok(None),
110        Ok(not_a_dictionary) => Err(Error::PropertiesExpectedObjectOrNull(not_a_dictionary)),
111        Err(e) => Err(e),
112    }
113}
114
115/// Retrieve a single Position from the value of the "coordinates" key
116///
117/// Used by Value::Point
118pub fn get_coords_one_pos(object: &mut JsonObject) -> Result<Position> {
119    let coords_json = get_coords_value(object)?;
120    json_to_position(&coords_json)
121}
122
123/// Retrieve a one dimensional Vec of Positions from the value of the "coordinates" key
124///
125/// Used by Value::MultiPoint and Value::LineString
126pub fn get_coords_1d_pos(object: &mut JsonObject) -> Result<Vec<Position>> {
127    let coords_json = get_coords_value(object)?;
128    json_to_1d_positions(&coords_json)
129}
130
131/// Retrieve a two dimensional Vec of Positions from the value of the "coordinates" key
132///
133/// Used by Value::MultiLineString and Value::Polygon
134pub fn get_coords_2d_pos(object: &mut JsonObject) -> Result<Vec<Vec<Position>>> {
135    let coords_json = get_coords_value(object)?;
136    json_to_2d_positions(&coords_json)
137}
138
139/// Retrieve a three dimensional Vec of Positions from the value of the "coordinates" key
140///
141/// Used by Value::MultiPolygon
142pub fn get_coords_3d_pos(object: &mut JsonObject) -> Result<Vec<Vec<Vec<Position>>>> {
143    let coords_json = get_coords_value(object)?;
144    json_to_3d_positions(&coords_json)
145}
146
147/// Used by Value::GeometryCollection
148pub fn get_geometries(object: &mut JsonObject) -> Result<Vec<Geometry>> {
149    let geometries_json = expect_property(object, "geometries")?;
150    let geometries_array = expect_owned_array(geometries_json)?;
151    let mut geometries = Vec::with_capacity(geometries_array.len());
152    for json in geometries_array {
153        let obj = expect_owned_object(json)?;
154        let geometry = Geometry::from_json_object(obj)?;
155        geometries.push(geometry);
156    }
157    Ok(geometries)
158}
159
160/// Used by Feature
161pub fn get_id(object: &mut JsonObject) -> Result<Option<feature::Id>> {
162    match object.remove("id") {
163        Some(JsonValue::Number(x)) => Ok(Some(feature::Id::Number(x))),
164        Some(JsonValue::String(s)) => Ok(Some(feature::Id::String(s))),
165        Some(v) => Err(Error::FeatureInvalidIdentifierType(v)),
166        None => Ok(None),
167    }
168}
169
170/// Used by Geometry, Value
171pub fn get_value(object: &mut JsonObject) -> Result<Value> {
172    let res = &*expect_type(object)?;
173    match res {
174        "Point" => Ok(Value::Point(get_coords_one_pos(object)?)),
175        "MultiPoint" => Ok(Value::MultiPoint(get_coords_1d_pos(object)?)),
176        "LineString" => Ok(Value::LineString(get_coords_1d_pos(object)?)),
177        "MultiLineString" => Ok(Value::MultiLineString(get_coords_2d_pos(object)?)),
178        "Polygon" => Ok(Value::Polygon(get_coords_2d_pos(object)?)),
179        "MultiPolygon" => Ok(Value::MultiPolygon(get_coords_3d_pos(object)?)),
180        "GeometryCollection" => Ok(Value::GeometryCollection(get_geometries(object)?)),
181        _ => Err(Error::GeometryUnknownType(res.to_string())),
182    }
183}
184
185/// Used by Feature
186pub fn get_geometry(object: &mut JsonObject) -> Result<Option<Geometry>> {
187    let geometry = expect_property(object, "geometry")?;
188    match geometry {
189        JsonValue::Object(x) => {
190            let geometry_object = Geometry::from_json_object(x)?;
191            Ok(Some(geometry_object))
192        }
193        JsonValue::Null => Ok(None),
194        _ => Err(Error::FeatureInvalidGeometryValue(geometry)),
195    }
196}
197
198/// Used by FeatureCollection
199pub fn get_features(object: &mut JsonObject) -> Result<Vec<Feature>> {
200    let prop = expect_property(object, "features")?;
201    let features_json = expect_owned_array(prop)?;
202    let mut features = Vec::with_capacity(features_json.len());
203    for feature in features_json {
204        let feature = expect_owned_object(feature)?;
205        let feature: Feature = Feature::from_json_object(feature)?;
206        features.push(feature);
207    }
208    Ok(features)
209}
210
211fn json_to_position(json: &JsonValue) -> Result<Position> {
212    let coords_array = expect_array(json)?;
213    if coords_array.len() < 2 {
214        return Err(Error::PositionTooShort(coords_array.len()));
215    }
216    let mut coords = Vec::with_capacity(coords_array.len());
217    for position in coords_array {
218        coords.push(expect_f64(position)?);
219    }
220    Ok(coords)
221}
222
223fn json_to_1d_positions(json: &JsonValue) -> Result<Vec<Position>> {
224    let coords_array = expect_array(json)?;
225    let mut coords = Vec::with_capacity(coords_array.len());
226    for item in coords_array {
227        coords.push(json_to_position(item)?);
228    }
229    Ok(coords)
230}
231
232fn json_to_2d_positions(json: &JsonValue) -> Result<Vec<Vec<Position>>> {
233    let coords_array = expect_array(json)?;
234    let mut coords = Vec::with_capacity(coords_array.len());
235    for item in coords_array {
236        coords.push(json_to_1d_positions(item)?);
237    }
238    Ok(coords)
239}
240
241fn json_to_3d_positions(json: &JsonValue) -> Result<Vec<Vec<Vec<Position>>>> {
242    let coords_array = expect_array(json)?;
243    let mut coords = Vec::with_capacity(coords_array.len());
244    for item in coords_array {
245        coords.push(json_to_2d_positions(item)?);
246    }
247    Ok(coords)
248}