1use std::collections::BTreeMap;
4use std::str::FromStr;
5
6use geo_types::Geometry;
7use serde::ser::SerializeMap as _;
8use serde::{Deserialize, Serialize};
9use serde_json::{Number, Value};
10
11use crate::decoder::PropValueRef;
12use crate::{LendingIterator, MltResult, ParsedLayer};
13
14#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
16pub struct FeatureCollection {
17 #[serde(rename = "type")]
18 pub ty: String,
19 pub features: Vec<Feature>,
20}
21
22impl FeatureCollection {
23 pub fn from_layers<'a>(layers: impl IntoIterator<Item = ParsedLayer<'a>>) -> MltResult<Self> {
26 let mut features = Vec::new();
27 for layer in layers {
28 let Some(parsed) = layer.into_layer01() else {
29 continue;
30 };
31 let layer_name = parsed.name();
32 let extent = parsed.extent().get();
33 let mut feat_iter = parsed.iter_features();
34 while let Some(feat) = feat_iter.next() {
35 let feat = feat?;
36 let mut properties = BTreeMap::new();
37 for p in feat.iter_properties() {
38 properties.insert(p.name().to_string(), p.value().into());
39 }
40 properties.insert("_layer".into(), Value::String(layer_name.to_string()));
41 properties.insert("_extent".into(), Value::Number(extent.into()));
42 features.push(Feature {
43 geometry: feat.geometry().clone(),
44 id: feat.id(),
45 properties,
46 ty: "Feature".into(),
47 });
48 }
49 }
50 Ok(Self {
51 features,
52 ty: "FeatureCollection".into(),
53 })
54 }
55
56 pub fn equals(&self, other: &Self) -> Result<bool, serde_json::Error> {
57 let self_val = normalize_tiny_floats(serde_json::to_value(self)?);
58 let other_val = normalize_tiny_floats(serde_json::to_value(other)?);
59 Ok(json_values_equal(&self_val, &other_val))
60 }
61}
62
63impl FromStr for FeatureCollection {
64 type Err = serde_json::Error;
65
66 fn from_str(s: &str) -> Result<Self, Self::Err> {
67 serde_json::from_str(s)
68 }
69}
70
71#[derive(Debug, Clone, PartialEq, Deserialize)]
73pub struct Feature {
74 #[serde(with = "geom_serde")]
75 pub geometry: Geometry<i32>,
76 #[serde(default, skip_serializing_if = "Option::is_none")]
77 pub id: Option<u64>,
78 #[serde(default)]
79 pub properties: BTreeMap<String, Value>,
80 #[serde(rename = "type")]
81 pub ty: String,
82}
83
84struct Geom32Wire<'a>(&'a Geometry<i32>);
85impl Serialize for Geom32Wire<'_> {
86 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
87 geom_serde::serialize(self.0, s)
88 }
89}
90
91impl Serialize for Feature {
93 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
94 let len = 3 + usize::from(self.id.is_some());
95 let mut map = serializer.serialize_map(Some(len))?;
96 map.serialize_entry("type", &self.ty)?;
97 if let Some(id) = self.id {
98 map.serialize_entry("id", &id)?;
99 }
100 map.serialize_entry("properties", &self.properties)?;
101 map.serialize_entry("geometry", &Geom32Wire(&self.geometry))?;
102 map.end()
103 }
104}
105
106mod geom_serde {
109 use geo_types::{
110 Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
111 };
112 use serde::de::Error as _;
113 use serde::ser::{Error, SerializeMap as _};
114 use serde::{Deserialize, Deserializer, Serializer};
115 use serde_json::Value;
116
117 type Arr = [i32; 2];
118
119 fn ls_arr(ls: &LineString<i32>) -> Vec<Arr> {
120 ls.0.iter().copied().map(Into::into).collect()
121 }
122
123 fn poly_arr(poly: &Polygon<i32>) -> Vec<Vec<Arr>> {
124 std::iter::once(poly.exterior())
125 .chain(poly.interiors())
126 .map(ls_arr)
127 .collect()
128 }
129
130 fn arr_ls(v: Vec<Arr>) -> LineString<i32> {
131 LineString::from(v)
132 }
133
134 fn arr_poly(rings: Vec<Vec<Arr>>) -> Polygon<i32> {
135 let mut it = rings.into_iter();
136 let ext = it.next().map_or_else(|| LineString(vec![]), arr_ls);
137 Polygon::new(ext, it.map(arr_ls).collect())
138 }
139
140 pub fn serialize<S: Serializer>(g: &Geometry<i32>, s: S) -> Result<S::Ok, S::Error> {
141 let mut m = s.serialize_map(Some(2))?;
142 let (ty, coords): (&str, Value) = match g {
143 Geometry::Point(p) => ("Point", serde_json::to_value(Arr::from(*p)).unwrap()),
144 Geometry::LineString(ls) => ("LineString", serde_json::to_value(ls_arr(ls)).unwrap()),
145 Geometry::Polygon(poly) => ("Polygon", serde_json::to_value(poly_arr(poly)).unwrap()),
146 Geometry::MultiPoint(mp) => (
147 "MultiPoint",
148 serde_json::to_value(mp.0.iter().copied().map(Arr::from).collect::<Vec<_>>())
149 .unwrap(),
150 ),
151 Geometry::MultiLineString(mls) => (
152 "MultiLineString",
153 serde_json::to_value(mls.iter().map(ls_arr).collect::<Vec<_>>()).unwrap(),
154 ),
155 Geometry::MultiPolygon(mpoly) => (
156 "MultiPolygon",
157 serde_json::to_value(mpoly.iter().map(poly_arr).collect::<Vec<_>>()).unwrap(),
158 ),
159 _ => return Err(Error::custom("unsupported geometry variant")),
160 };
161 m.serialize_entry("type", ty)?;
162 m.serialize_entry("coordinates", &coords)?;
163 m.end()
164 }
165
166 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Geometry<i32>, D::Error> {
167 fn parse<T: serde::de::DeserializeOwned, E: serde::de::Error>(v: Value) -> Result<T, E> {
168 serde_json::from_value(v).map_err(E::custom)
169 }
170
171 #[derive(Deserialize)]
172 struct Wire {
173 #[serde(rename = "type")]
174 ty: String,
175 coordinates: Value,
176 }
177
178 let Wire { ty, coordinates: c } = Wire::deserialize(d)?;
179 Ok(match ty.as_str() {
180 "Point" => Geometry::Point(Point::from(parse::<Arr, _>(c)?)),
181 "LineString" => Geometry::LineString(arr_ls(parse(c)?)),
182 "Polygon" => Geometry::Polygon(arr_poly(parse(c)?)),
183 "MultiPoint" => {
184 let v: Vec<Arr> = parse(c)?;
185 Geometry::MultiPoint(MultiPoint(v.into_iter().map(Point::from).collect()))
186 }
187 "MultiLineString" => {
188 let v: Vec<Vec<Arr>> = parse(c)?;
189 Geometry::MultiLineString(MultiLineString(v.into_iter().map(arr_ls).collect()))
190 }
191 "MultiPolygon" => {
192 let v: Vec<Vec<Vec<Arr>>> = parse(c)?;
193 Geometry::MultiPolygon(MultiPolygon(v.into_iter().map(arr_poly).collect()))
194 }
195 _ => {
196 return Err(D::Error::unknown_variant(
197 &ty,
198 &[
199 "Point",
200 "LineString",
201 "Polygon",
202 "MultiPoint",
203 "MultiLineString",
204 "MultiPolygon",
205 ],
206 ));
207 }
208 })
209 }
210}
211
212#[must_use]
214pub fn f32_to_json(f: f32) -> Value {
215 if f.is_nan() {
216 Value::String("f32::NAN".to_owned())
217 } else if f == f32::INFINITY {
218 Value::String("f32::INFINITY".to_owned())
219 } else if f == f32::NEG_INFINITY {
220 Value::String("f32::NEG_INFINITY".to_owned())
221 } else {
222 Number::from_f64(f64::from(f)).expect("finite f32").into()
223 }
224}
225
226#[must_use]
228pub fn f64_to_json(f: f64) -> Value {
229 if f.is_nan() {
230 Value::String("f64::NAN".to_owned())
231 } else if f == f64::INFINITY {
232 Value::String("f64::INFINITY".to_owned())
233 } else if f == f64::NEG_INFINITY {
234 Value::String("f64::NEG_INFINITY".to_owned())
235 } else {
236 Number::from_f64(f).expect("finite f64").into()
237 }
238}
239
240impl From<PropValueRef<'_>> for Value {
241 fn from(v: PropValueRef<'_>) -> Self {
242 match v {
243 PropValueRef::Bool(v) => Self::Bool(v),
244 PropValueRef::I8(v) => Self::from(v),
245 PropValueRef::U8(v) => Self::from(v),
246 PropValueRef::I32(v) => Self::from(v),
247 PropValueRef::U32(v) => Self::from(v),
248 PropValueRef::I64(v) => Self::from(v),
249 PropValueRef::U64(v) => Self::from(v),
250 PropValueRef::F32(v) => f32_to_json(v),
251 PropValueRef::F64(v) => f64_to_json(v),
252 PropValueRef::Str(s) => Self::String(s.to_string()),
253 }
254 }
255}
256
257fn normalize_tiny_floats(value: Value) -> Value {
259 match value {
260 Value::Number(ref n) => {
261 let eps = f64::from(f32::EPSILON);
262 if let Some(f) = n.as_f64()
263 && f.is_finite()
264 && f.abs() < eps
265 {
266 Value::from(0.0)
267 } else {
268 value
269 }
270 }
271 Value::Array(arr) => Value::Array(arr.into_iter().map(normalize_tiny_floats).collect()),
272 Value::Object(obj) => Value::Object(
273 obj.into_iter()
274 .map(|(k, v)| (k, normalize_tiny_floats(v)))
275 .collect(),
276 ),
277 v => v,
278 }
279}
280
281fn json_values_equal(a: &Value, b: &Value) -> bool {
285 match (a, b) {
286 (Value::Number(na), Value::Number(nb)) if na.is_f64() && nb.is_f64() => {
287 let na = na.as_f64().expect("f64");
288 let nb = nb.as_f64().expect("f64");
289 assert!(
290 !na.is_nan() && !nb.is_nan(),
291 "unexpected non-finite numbers"
292 );
293 let abs_diff = (na - nb).abs();
294 let max_abs = na.abs().max(nb.abs()).max(1.0);
295 abs_diff <= f64::from(f32::EPSILON) * max_abs * 2.0
296 }
297 (Value::Array(aa), Value::Array(ab)) => {
298 aa.len() == ab.len()
299 && aa
300 .iter()
301 .zip(ab.iter())
302 .all(|(x, y)| json_values_equal(x, y))
303 }
304 (Value::Object(ao), Value::Object(bo)) => {
305 ao.len() == bo.len()
306 && ao
307 .iter()
308 .all(|(k, v)| bo.get(k).is_some_and(|w| json_values_equal(v, w)))
309 }
310 _ => a == b,
311 }
312}