use crate::{GeoJsonResult, Geometry, Id, Value, helpers::geojson_wrapper};
use tracing::instrument;
geojson_wrapper!(Feature, geojson::Feature);
elicitation::elicit_newtype_traits!(Feature, geojson::Feature, [display, from_str]);
impl From<Geometry> for Feature {
fn from(value: Geometry) -> Self {
Self::from(geojson::Feature::from(geojson::Geometry::from(value)))
}
}
impl From<Value> for Feature {
fn from(value: Value) -> Self {
Self::from(geojson::Feature::from(geojson::GeometryValue::from(value)))
}
}
impl TryFrom<Feature> for elicit_geo_types::Geometry {
type Error = geojson::Error;
fn try_from(value: Feature) -> Result<Self, Self::Error> {
let geometry = geo_types::Geometry::<f64>::try_from(geojson::Feature::from(value))?;
Ok(crate::helpers::wrap_geo_geometry(geometry))
}
}
impl Feature {
#[instrument]
pub fn from_json_object(object: geojson::JsonObject) -> GeoJsonResult<Self> {
serde_json::from_value(serde_json::Value::Object(object))
.map(|f: geojson::Feature| Self::from(f))
.map_err(|e| Box::new(geojson::Error::from(e)))
}
#[instrument]
pub fn from_json_value(value: serde_json::Value) -> GeoJsonResult<Self> {
serde_json::from_value(value)
.map(|f: geojson::Feature| Self::from(f))
.map_err(|e| Box::new(geojson::Error::from(e)))
}
#[instrument(skip(self, key))]
pub fn property(&self, key: impl AsRef<str>) -> Option<&geojson::JsonValue> {
self.0.property(key)
}
#[instrument(skip(self, key))]
pub fn contains_property(&self, key: impl AsRef<str>) -> bool {
self.0.contains_property(key)
}
#[instrument(skip(self, key, value))]
pub fn set_property(&mut self, key: impl Into<String>, value: impl Into<geojson::JsonValue>) {
std::sync::Arc::make_mut(&mut self.0).set_property(key, value);
}
#[instrument(skip(self, key))]
pub fn remove_property(&mut self, key: impl AsRef<str>) -> Option<geojson::JsonValue> {
std::sync::Arc::make_mut(&mut self.0).remove_property(key)
}
#[instrument(skip(self))]
pub fn len_properties(&self) -> usize {
self.0.len_properties()
}
#[instrument(skip(self))]
pub fn properties_iter(
&self,
) -> Box<dyn ExactSizeIterator<Item = (&String, &geojson::JsonValue)> + '_> {
self.0.properties_iter()
}
#[instrument(skip(self))]
pub fn id(&self) -> Option<Id> {
self.0.id.clone().map(Id::from)
}
}
mod emit_impls {
use super::Feature;
impl elicitation::emit_code::ToCodeLiteral for Feature {
fn to_code_literal(&self) -> proc_macro2::TokenStream {
let json = serde_json::to_string(&*self.0).expect("Feature is serializable");
quote::quote! {
::elicit_geojson::Feature::from(
::serde_json::from_str::<::geojson::Feature>(#json)
.expect("valid Feature JSON")
)
}
}
}
}
impl elicitation::ElicitComplete for Feature {}