use crate::errors::{Error, Result};
use crate::{feature, Bbox, Feature, Geometry, Position, Value};
use crate::{JsonObject, JsonValue};
pub fn expect_type(value: &mut JsonObject) -> Result<String> {
let prop = expect_property(value, "type")?;
expect_string(prop)
}
pub fn expect_string(value: JsonValue) -> Result<String> {
match value {
JsonValue::String(s) => Ok(s),
_ => Err(Error::ExpectedStringValue(value)),
}
}
pub fn expect_f64(value: &JsonValue) -> Result<f64> {
match value.as_f64() {
Some(v) => Ok(v),
None => Err(Error::ExpectedF64Value),
}
}
pub fn expect_array(value: &JsonValue) -> Result<&Vec<JsonValue>> {
match value.as_array() {
Some(v) => Ok(v),
None => Err(Error::ExpectedArrayValue("None".to_string())),
}
}
fn expect_property(obj: &mut JsonObject, name: &'static str) -> Result<JsonValue> {
match obj.remove(name) {
Some(v) => Ok(v),
None => Err(Error::ExpectedProperty(name.to_string())),
}
}
fn expect_owned_array(value: JsonValue) -> Result<Vec<JsonValue>> {
match value {
JsonValue::Array(v) => Ok(v),
_ => match value {
JsonValue::Array(_) => Err(Error::ExpectedArrayValue("Array".to_string())),
JsonValue::Null => Err(Error::ExpectedArrayValue("Null".to_string())),
JsonValue::Bool(_) => Err(Error::ExpectedArrayValue("Bool".to_string())),
JsonValue::Number(_) => Err(Error::ExpectedArrayValue("Number".to_string())),
JsonValue::String(_) => Err(Error::ExpectedArrayValue("String".to_string())),
JsonValue::Object(_) => Err(Error::ExpectedArrayValue("Object".to_string())),
},
}
}
pub(crate) fn expect_owned_object(value: JsonValue) -> Result<JsonObject> {
match value {
JsonValue::Object(o) => Ok(o),
_ => Err(Error::ExpectedObjectValue(value)),
}
}
pub fn get_coords_value(object: &mut JsonObject) -> Result<JsonValue> {
expect_property(object, "coordinates")
}
pub fn get_bbox(object: &mut JsonObject) -> Result<Option<Bbox>> {
let bbox_json = match object.remove("bbox") {
Some(b) => b,
None => return Ok(None),
};
let bbox_array = match bbox_json {
JsonValue::Array(a) => a,
_ => return Err(Error::BboxExpectedArray(bbox_json)),
};
let bbox = bbox_array
.into_iter()
.map(|i| i.as_f64().ok_or(Error::BboxExpectedNumericValues(i)))
.collect::<Result<Vec<_>>>()?;
Ok(Some(bbox))
}
pub fn get_foreign_members(object: JsonObject) -> Result<Option<JsonObject>> {
if object.is_empty() {
Ok(None)
} else {
Ok(Some(object))
}
}
pub fn get_properties(object: &mut JsonObject) -> Result<Option<JsonObject>> {
let properties = expect_property(object, "properties");
match properties {
Ok(JsonValue::Object(x)) => Ok(Some(x)),
Ok(JsonValue::Null) | Err(Error::ExpectedProperty(_)) => Ok(None),
Ok(not_a_dictionary) => Err(Error::PropertiesExpectedObjectOrNull(not_a_dictionary)),
Err(e) => Err(e),
}
}
pub fn get_coords_one_pos(object: &mut JsonObject) -> Result<Position> {
let coords_json = get_coords_value(object)?;
json_to_position(&coords_json)
}
pub fn get_coords_1d_pos(object: &mut JsonObject) -> Result<Vec<Position>> {
let coords_json = get_coords_value(object)?;
json_to_1d_positions(&coords_json)
}
pub fn get_coords_2d_pos(object: &mut JsonObject) -> Result<Vec<Vec<Position>>> {
let coords_json = get_coords_value(object)?;
json_to_2d_positions(&coords_json)
}
pub fn get_coords_3d_pos(object: &mut JsonObject) -> Result<Vec<Vec<Vec<Position>>>> {
let coords_json = get_coords_value(object)?;
json_to_3d_positions(&coords_json)
}
pub fn get_geometries(object: &mut JsonObject) -> Result<Vec<Geometry>> {
let geometries_json = expect_property(object, "geometries")?;
let geometries_array = expect_owned_array(geometries_json)?;
let mut geometries = Vec::with_capacity(geometries_array.len());
for json in geometries_array {
let obj = expect_owned_object(json)?;
let geometry = Geometry::from_json_object(obj)?;
geometries.push(geometry);
}
Ok(geometries)
}
pub fn get_id(object: &mut JsonObject) -> Result<Option<feature::Id>> {
match object.remove("id") {
Some(JsonValue::Number(x)) => Ok(Some(feature::Id::Number(x))),
Some(JsonValue::String(s)) => Ok(Some(feature::Id::String(s))),
Some(v) => Err(Error::FeatureInvalidIdentifierType(v)),
None => Ok(None),
}
}
pub fn get_value(object: &mut JsonObject) -> Result<Value> {
let res = &*expect_type(object)?;
match res {
"Point" => Ok(Value::Point(get_coords_one_pos(object)?)),
"MultiPoint" => Ok(Value::MultiPoint(get_coords_1d_pos(object)?)),
"LineString" => Ok(Value::LineString(get_coords_1d_pos(object)?)),
"MultiLineString" => Ok(Value::MultiLineString(get_coords_2d_pos(object)?)),
"Polygon" => Ok(Value::Polygon(get_coords_2d_pos(object)?)),
"MultiPolygon" => Ok(Value::MultiPolygon(get_coords_3d_pos(object)?)),
"GeometryCollection" => Ok(Value::GeometryCollection(get_geometries(object)?)),
_ => Err(Error::GeometryUnknownType(res.to_string())),
}
}
pub fn get_geometry(object: &mut JsonObject) -> Result<Option<Geometry>> {
let geometry = expect_property(object, "geometry")?;
match geometry {
JsonValue::Object(x) => {
let geometry_object = Geometry::from_json_object(x)?;
Ok(Some(geometry_object))
}
JsonValue::Null => Ok(None),
_ => Err(Error::FeatureInvalidGeometryValue(geometry)),
}
}
pub fn get_features(object: &mut JsonObject) -> Result<Vec<Feature>> {
let prop = expect_property(object, "features")?;
let features_json = expect_owned_array(prop)?;
let mut features = Vec::with_capacity(features_json.len());
for feature in features_json {
let feature = expect_owned_object(feature)?;
let feature: Feature = Feature::from_json_object(feature)?;
features.push(feature);
}
Ok(features)
}
fn json_to_position(json: &JsonValue) -> Result<Position> {
let coords_array = expect_array(json)?;
if coords_array.len() < 2 {
return Err(Error::PositionTooShort(coords_array.len()));
}
let mut coords = Vec::with_capacity(coords_array.len());
for position in coords_array {
coords.push(expect_f64(position)?);
}
Ok(coords)
}
fn json_to_1d_positions(json: &JsonValue) -> Result<Vec<Position>> {
let coords_array = expect_array(json)?;
let mut coords = Vec::with_capacity(coords_array.len());
for item in coords_array {
coords.push(json_to_position(item)?);
}
Ok(coords)
}
fn json_to_2d_positions(json: &JsonValue) -> Result<Vec<Vec<Position>>> {
let coords_array = expect_array(json)?;
let mut coords = Vec::with_capacity(coords_array.len());
for item in coords_array {
coords.push(json_to_1d_positions(item)?);
}
Ok(coords)
}
fn json_to_3d_positions(json: &JsonValue) -> Result<Vec<Vec<Vec<Position>>>> {
let coords_array = expect_array(json)?;
let mut coords = Vec::with_capacity(coords_array.len());
for item in coords_array {
coords.push(json_to_2d_positions(item)?);
}
Ok(coords)
}