use crate::errors::Error;
use crate::json::{JsonObject, JsonValue};
use crate::{feature, Bbox, Feature, Geometry, Position, Value};
pub fn expect_type(value: &mut JsonObject) -> Result<String, Error> {
let prop = expect_property(value, "type")?;
expect_string(prop)
}
pub fn expect_string(value: JsonValue) -> Result<String, Error> {
match value {
JsonValue::String(s) => Ok(s),
_ => Err(Error::ExpectedStringValue(value)),
}
}
pub fn expect_f64(value: &JsonValue) -> Result<f64, Error> {
match value.as_f64() {
Some(v) => Ok(v),
None => Err(Error::ExpectedF64Value),
}
}
pub fn expect_array(value: &JsonValue) -> Result<&Vec<JsonValue>, Error> {
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, Error> {
match obj.remove(name) {
Some(v) => Ok(v),
None => Err(Error::ExpectedProperty(name.to_string())),
}
}
fn expect_owned_array(value: JsonValue) -> Result<Vec<JsonValue>, Error> {
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())),
},
}
}
fn expect_owned_object(value: JsonValue) -> Result<JsonObject, Error> {
match value {
JsonValue::Object(o) => Ok(o),
_ => Err(Error::ExpectedObjectValue(value)),
}
}
pub fn get_coords_value(object: &mut JsonObject) -> Result<JsonValue, Error> {
expect_property(object, "coordinates")
}
pub fn get_bbox(object: &mut JsonObject) -> Result<Option<Bbox>, Error> {
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>, Error> {
if object.is_empty() {
Ok(None)
} else {
Ok(Some(object))
}
}
pub fn get_properties(object: &mut JsonObject) -> Result<Option<JsonObject>, Error> {
let properties = expect_property(object, "properties")?;
match properties {
JsonValue::Object(x) => Ok(Some(x)),
JsonValue::Null => Ok(None),
_ => Err(Error::PropertiesExpectedObjectOrNull(properties)),
}
}
pub fn get_coords_one_pos(object: &mut JsonObject) -> Result<Position, Error> {
let coords_json = get_coords_value(object)?;
json_to_position(&coords_json)
}
pub fn get_coords_1d_pos(object: &mut JsonObject) -> Result<Vec<Position>, Error> {
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>>, Error> {
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>>>, Error> {
let coords_json = get_coords_value(object)?;
json_to_3d_positions(&coords_json)
}
pub fn get_geometries(object: &mut JsonObject) -> Result<Vec<Geometry>, Error> {
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>, Error> {
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, Error> {
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>, Error> {
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>, Error> {
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, Error> {
let coords_array = expect_array(json)?;
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>, Error> {
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>>, Error> {
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>>>, Error> {
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)
}