use std::{convert::TryFrom, fmt};
use crate::errors::Error;
use crate::json::{Deserialize, Deserializer, JsonObject, JsonValue, Serialize, Serializer};
use crate::serde;
use crate::{util, Bbox, LineStringType, PointType, PolygonType};
#[derive(Clone, Debug, PartialEq)]
pub enum Value {
Point(PointType),
MultiPoint(Vec<PointType>),
LineString(LineStringType),
MultiLineString(Vec<LineStringType>),
Polygon(PolygonType),
MultiPolygon(Vec<PolygonType>),
GeometryCollection(Vec<Geometry>),
}
impl<'a> From<&'a Value> for JsonObject {
fn from(value: &'a Value) -> JsonObject {
let mut map = JsonObject::new();
let ty = String::from(match value {
Value::Point(..) => "Point",
Value::MultiPoint(..) => "MultiPoint",
Value::LineString(..) => "LineString",
Value::MultiLineString(..) => "MultiLineString",
Value::Polygon(..) => "Polygon",
Value::MultiPolygon(..) => "MultiPolygon",
Value::GeometryCollection(..) => "GeometryCollection",
});
map.insert(String::from("type"), ::serde_json::to_value(&ty).unwrap());
map.insert(
String::from(match value {
Value::GeometryCollection(..) => "geometries",
_ => "coordinates",
}),
::serde_json::to_value(&value).unwrap(),
);
map
}
}
impl Value {
pub fn from_json_object(object: JsonObject) -> Result<Self, Error> {
Self::try_from(object)
}
pub fn from_json_value(value: JsonValue) -> Result<Self, Error> {
Self::try_from(value)
}
}
impl TryFrom<JsonObject> for Value {
type Error = Error;
fn try_from(mut object: JsonObject) -> Result<Self, Self::Error> {
util::get_value(&mut object)
}
}
impl TryFrom<JsonValue> for Value {
type Error = Error;
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
if let JsonValue::Object(obj) = value {
Self::try_from(obj)
} else {
Err(Error::GeoJsonExpectedObject(value))
}
}
}
impl fmt::Display for Value {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
::serde_json::to_string(&JsonObject::from(self))
.map_err(|_| fmt::Error)
.and_then(|s| f.write_str(&s))
}
}
impl<'a> From<&'a Value> for JsonValue {
fn from(value: &'a Value) -> JsonValue {
match *value {
Value::Point(ref x) => ::serde_json::to_value(x),
Value::MultiPoint(ref x) => ::serde_json::to_value(x),
Value::LineString(ref x) => ::serde_json::to_value(x),
Value::MultiLineString(ref x) => ::serde_json::to_value(x),
Value::Polygon(ref x) => ::serde_json::to_value(x),
Value::MultiPolygon(ref x) => ::serde_json::to_value(x),
Value::GeometryCollection(ref x) => ::serde_json::to_value(x),
}
.unwrap()
}
}
impl Serialize for Value {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
JsonValue::from(self).serialize(serializer)
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Geometry {
pub bbox: Option<Bbox>,
pub value: Value,
pub foreign_members: Option<JsonObject>,
}
impl Geometry {
pub fn new(value: Value) -> Self {
Geometry {
bbox: None,
value,
foreign_members: None,
}
}
}
impl<'a> From<&'a Geometry> for JsonObject {
fn from(geometry: &'a Geometry) -> JsonObject {
let mut map = JsonObject::from(&geometry.value);
if let Some(ref bbox) = geometry.bbox {
map.insert(String::from("bbox"), ::serde_json::to_value(bbox).unwrap());
}
if let Some(ref foreign_members) = geometry.foreign_members {
for (key, value) in foreign_members {
map.insert(key.to_owned(), value.to_owned());
}
}
map
}
}
impl Geometry {
pub fn from_json_object(object: JsonObject) -> Result<Self, Error> {
Self::try_from(object)
}
pub fn from_json_value(value: JsonValue) -> Result<Self, Error> {
Self::try_from(value)
}
}
impl TryFrom<JsonObject> for Geometry {
type Error = Error;
fn try_from(mut object: JsonObject) -> Result<Self, Self::Error> {
let bbox = util::get_bbox(&mut object)?;
let value = util::get_value(&mut object)?;
let foreign_members = util::get_foreign_members(object)?;
Ok(Geometry {
bbox,
value,
foreign_members,
})
}
}
impl TryFrom<JsonValue> for Geometry {
type Error = Error;
fn try_from(value: JsonValue) -> Result<Self, Self::Error> {
if let JsonValue::Object(obj) = value {
Self::try_from(obj)
} else {
Err(Error::GeoJsonExpectedObject(value))
}
}
}
impl Serialize for Geometry {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
JsonObject::from(self).serialize(serializer)
}
}
impl<'de> Deserialize<'de> for Geometry {
fn deserialize<D>(deserializer: D) -> Result<Geometry, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error as SerdeError;
let val = JsonObject::deserialize(deserializer)?;
Geometry::from_json_object(val).map_err(|e| D::Error::custom(e.to_string()))
}
}
impl<V> From<V> for Geometry
where
V: Into<Value>,
{
fn from(v: V) -> Geometry {
Geometry::new(v.into())
}
}
#[cfg(test)]
mod tests {
use crate::json::JsonObject;
use crate::{GeoJson, Geometry, Value};
fn encode(geometry: &Geometry) -> String {
serde_json::to_string(&geometry).unwrap()
}
fn decode(json_string: String) -> GeoJson {
json_string.parse().unwrap()
}
#[test]
fn encode_decode_geometry() {
let geometry_json_str = "{\"coordinates\":[1.1,2.1],\"type\":\"Point\"}";
let geometry = Geometry {
value: Value::Point(vec![1.1, 2.1]),
bbox: None,
foreign_members: None,
};
let json_string = encode(&geometry);
assert_eq!(json_string, geometry_json_str);
let decoded_geometry = match decode(json_string) {
GeoJson::Geometry(g) => g,
_ => unreachable!(),
};
assert_eq!(decoded_geometry, geometry);
}
#[test]
fn test_geometry_from_value() {
use serde_json::json;
use std::convert::TryInto;
let json_value = json!({
"type": "Point",
"coordinates": [
0.0, 0.1
],
});
assert!(json_value.is_object());
let geometry: Geometry = json_value.try_into().unwrap();
assert_eq!(
geometry,
Geometry {
value: Value::Point(vec![0.0, 0.1]),
bbox: None,
foreign_members: None,
}
)
}
#[test]
fn test_geometry_display() {
let v = Value::LineString(vec![vec![0.0, 0.1], vec![0.1, 0.2], vec![0.2, 0.3]]);
let geometry = Geometry::new(v);
assert_eq!(
"{\"coordinates\":[[0.0,0.1],[0.1,0.2],[0.2,0.3]],\"type\":\"LineString\"}",
geometry.to_string()
);
}
#[test]
fn test_value_display() {
let v = Value::LineString(vec![vec![0.0, 0.1], vec![0.1, 0.2], vec![0.2, 0.3]]);
assert_eq!(
"{\"coordinates\":[[0.0,0.1],[0.1,0.2],[0.2,0.3]],\"type\":\"LineString\"}",
v.to_string()
);
}
#[test]
fn encode_decode_geometry_with_foreign_member() {
let geometry_json_str =
"{\"coordinates\":[1.1,2.1],\"other_member\":true,\"type\":\"Point\"}";
let mut foreign_members = JsonObject::new();
foreign_members.insert(
String::from("other_member"),
serde_json::to_value(true).unwrap(),
);
let geometry = Geometry {
value: Value::Point(vec![1.1, 2.1]),
bbox: None,
foreign_members: Some(foreign_members),
};
let json_string = encode(&geometry);
assert_eq!(json_string, geometry_json_str);
let decoded_geometry = match decode(geometry_json_str.into()) {
GeoJson::Geometry(g) => g,
_ => unreachable!(),
};
assert_eq!(decoded_geometry, geometry);
}
#[test]
fn encode_decode_geometry_collection() {
let geometry_collection = Geometry {
bbox: None,
value: Value::GeometryCollection(vec![
Geometry {
bbox: None,
value: Value::Point(vec![100.0, 0.0]),
foreign_members: None,
},
Geometry {
bbox: None,
value: Value::LineString(vec![vec![101.0, 0.0], vec![102.0, 1.0]]),
foreign_members: None,
},
]),
foreign_members: None,
};
let geometry_collection_string = "{\"geometries\":[{\"coordinates\":[100.0,0.0],\"type\":\"Point\"},{\"coordinates\":[[101.0,0.0],[102.0,1.0]],\"type\":\"LineString\"}],\"type\":\"GeometryCollection\"}";
let json_string = encode(&geometry_collection);
assert_eq!(json_string, geometry_collection_string);
let decoded_geometry = match decode(geometry_collection_string.into()) {
GeoJson::Geometry(g) => g,
_ => unreachable!(),
};
assert_eq!(decoded_geometry, geometry_collection);
}
}