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#[cfg(feature = "unstable-v2")]
14use crate::{
15 ParsedLayer01,
16 tile::{MValue, NestedValue},
17};
18
19#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct FeatureCollection {
22 #[serde(rename = "type")]
23 pub ty: String,
24 pub features: Vec<Feature>,
25}
26
27impl FeatureCollection {
28 pub fn from_layers<'a>(layers: impl IntoIterator<Item = ParsedLayer<'a>>) -> MltResult<Self> {
31 let mut features = Vec::new();
32 for layer in layers {
33 let Some(parsed) = layer.into_layer01() else {
34 continue;
35 };
36 let layer_name = parsed.name();
37 let extent = parsed.extent().get();
38 #[cfg(feature = "unstable-v2")]
41 let mut m_values = m_value_properties(&parsed)?.into_iter();
42 #[cfg(feature = "unstable-v2")]
45 let mut nested = nested_properties(&parsed)?.into_iter();
46 let mut feat_iter = parsed.iter_features();
47 while let Some(feat) = feat_iter.next() {
48 let feat = feat?;
49 let mut properties = BTreeMap::new();
50 for p in feat.iter_properties() {
51 properties.insert(p.name().to_string(), p.value().into());
52 }
53 #[cfg(feature = "unstable-v2")]
54 properties.extend(m_values.next().unwrap_or_default());
55 #[cfg(feature = "unstable-v2")]
56 properties.extend(nested.next().unwrap_or_default());
57 properties.insert("_layer".into(), Value::String(layer_name.to_string()));
58 properties.insert("_extent".into(), Value::Number(extent.into()));
59 features.push(Feature {
60 geometry: feat.geometry().clone(),
61 id: feat.id(),
62 properties,
63 ty: "Feature".into(),
64 });
65 }
66 }
67 Ok(Self {
68 features,
69 ty: "FeatureCollection".into(),
70 })
71 }
72
73 pub fn equals(&self, other: &Self) -> Result<bool, serde_json::Error> {
74 let self_val = normalize_tiny_floats(serde_json::to_value(self)?);
75 let other_val = normalize_tiny_floats(serde_json::to_value(other)?);
76 Ok(json_values_equal(&self_val, &other_val))
77 }
78}
79
80impl FromStr for FeatureCollection {
81 type Err = serde_json::Error;
82
83 fn from_str(s: &str) -> Result<Self, Self::Err> {
84 serde_json::from_str(s)
85 }
86}
87
88#[derive(Debug, Clone, PartialEq, Deserialize)]
90pub struct Feature {
91 #[serde(with = "geom_serde")]
92 pub geometry: Geometry<i32>,
93 #[serde(default, skip_serializing_if = "Option::is_none")]
94 pub id: Option<u64>,
95 #[serde(default)]
96 pub properties: BTreeMap<String, Value>,
97 #[serde(rename = "type")]
98 pub ty: String,
99}
100
101struct Geom32Wire<'a>(&'a Geometry<i32>);
102impl Serialize for Geom32Wire<'_> {
103 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
104 geom_serde::serialize(self.0, s)
105 }
106}
107
108impl Serialize for Feature {
110 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
111 let len = 3 + usize::from(self.id.is_some());
112 let mut map = serializer.serialize_map(Some(len))?;
113 map.serialize_entry("type", &self.ty)?;
114 if let Some(id) = self.id {
115 map.serialize_entry("id", &id)?;
116 }
117 map.serialize_entry("properties", &self.properties)?;
118 map.serialize_entry("geometry", &Geom32Wire(&self.geometry))?;
119 map.end()
120 }
121}
122
123mod geom_serde {
126 use geo_types::{
127 Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
128 };
129 use serde::de::Error as _;
130 use serde::ser::{Error, SerializeMap as _};
131 use serde::{Deserialize, Deserializer, Serializer};
132 use serde_json::Value;
133
134 type Arr = [i32; 2];
135
136 fn ls_arr(ls: &LineString<i32>) -> Vec<Arr> {
137 ls.0.iter().copied().map(Into::into).collect()
138 }
139
140 fn poly_arr(poly: &Polygon<i32>) -> Vec<Vec<Arr>> {
141 std::iter::once(poly.exterior())
142 .chain(poly.interiors())
143 .map(ls_arr)
144 .collect()
145 }
146
147 fn arr_ls(v: Vec<Arr>) -> LineString<i32> {
148 LineString::from(v)
149 }
150
151 fn arr_poly(rings: Vec<Vec<Arr>>) -> Polygon<i32> {
152 let mut it = rings.into_iter();
153 let ext = it.next().map_or_else(|| LineString(vec![]), arr_ls);
154 Polygon::new(ext, it.map(arr_ls).collect())
155 }
156
157 pub fn serialize<S: Serializer>(g: &Geometry<i32>, s: S) -> Result<S::Ok, S::Error> {
158 let mut m = s.serialize_map(Some(2))?;
159 let (ty, coords): (&str, Value) = match g {
160 Geometry::Point(p) => ("Point", serde_json::to_value(Arr::from(*p)).unwrap()),
161 Geometry::LineString(ls) => ("LineString", serde_json::to_value(ls_arr(ls)).unwrap()),
162 Geometry::Polygon(poly) => ("Polygon", serde_json::to_value(poly_arr(poly)).unwrap()),
163 Geometry::MultiPoint(mp) => (
164 "MultiPoint",
165 serde_json::to_value(mp.0.iter().copied().map(Arr::from).collect::<Vec<_>>())
166 .unwrap(),
167 ),
168 Geometry::MultiLineString(mls) => (
169 "MultiLineString",
170 serde_json::to_value(mls.iter().map(ls_arr).collect::<Vec<_>>()).unwrap(),
171 ),
172 Geometry::MultiPolygon(mpoly) => (
173 "MultiPolygon",
174 serde_json::to_value(mpoly.iter().map(poly_arr).collect::<Vec<_>>()).unwrap(),
175 ),
176 Geometry::Line(_)
177 | Geometry::Rect(_)
178 | Geometry::Triangle(_)
179 | Geometry::GeometryCollection(_) => {
180 return Err(Error::custom("unsupported geometry variant"));
181 }
182 };
183 m.serialize_entry("type", ty)?;
184 m.serialize_entry("coordinates", &coords)?;
185 m.end()
186 }
187
188 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Geometry<i32>, D::Error> {
189 fn parse<T: serde::de::DeserializeOwned, E: serde::de::Error>(v: Value) -> Result<T, E> {
190 serde_json::from_value(v).map_err(E::custom)
191 }
192
193 #[derive(Deserialize)]
194 struct Wire {
195 #[serde(rename = "type")]
196 ty: String,
197 coordinates: Value,
198 }
199
200 let Wire { ty, coordinates: c } = Wire::deserialize(d)?;
201 Ok(match ty.as_str() {
202 "Point" => Geometry::Point(Point::from(parse::<Arr, _>(c)?)),
203 "LineString" => Geometry::LineString(arr_ls(parse(c)?)),
204 "Polygon" => Geometry::Polygon(arr_poly(parse(c)?)),
205 "MultiPoint" => {
206 let v: Vec<Arr> = parse(c)?;
207 Geometry::MultiPoint(MultiPoint(v.into_iter().map(Point::from).collect()))
208 }
209 "MultiLineString" => {
210 let v: Vec<Vec<Arr>> = parse(c)?;
211 Geometry::MultiLineString(MultiLineString(v.into_iter().map(arr_ls).collect()))
212 }
213 "MultiPolygon" => {
214 let v: Vec<Vec<Vec<Arr>>> = parse(c)?;
215 Geometry::MultiPolygon(MultiPolygon(v.into_iter().map(arr_poly).collect()))
216 }
217 _ => {
218 return Err(D::Error::unknown_variant(
219 &ty,
220 &[
221 "Point",
222 "LineString",
223 "Polygon",
224 "MultiPoint",
225 "MultiLineString",
226 "MultiPolygon",
227 ],
228 ));
229 }
230 })
231 }
232}
233
234#[must_use]
236pub fn f32_to_json(f: f32) -> Value {
237 if f.is_nan() {
238 Value::String("f32::NAN".to_owned())
239 } else if f == f32::INFINITY {
240 Value::String("f32::INFINITY".to_owned())
241 } else if f == f32::NEG_INFINITY {
242 Value::String("f32::NEG_INFINITY".to_owned())
243 } else {
244 Number::from_f64(f64::from(f)).expect("finite f32").into()
245 }
246}
247
248#[must_use]
250pub fn f64_to_json(f: f64) -> Value {
251 if f.is_nan() {
252 Value::String("f64::NAN".to_owned())
253 } else if f == f64::INFINITY {
254 Value::String("f64::INFINITY".to_owned())
255 } else if f == f64::NEG_INFINITY {
256 Value::String("f64::NEG_INFINITY".to_owned())
257 } else {
258 Number::from_f64(f).expect("finite f64").into()
259 }
260}
261
262#[cfg(feature = "unstable-v2")]
267fn m_value_properties(layer: &ParsedLayer01<'_>) -> MltResult<Vec<Vec<(String, Value)>>> {
268 let geometry = layer.geometry_values();
269 let mut features = vec![Vec::new(); geometry.feature_count()];
270 for column in layer.m_values() {
271 let key = format!("m:{}", column.name());
272 for (index, span) in column.spans(geometry).enumerate() {
273 let values = column.values().row(column.name(), span?)?;
274 if let Some(value) = m_value_to_json(&values) {
275 features[index].push((key.clone(), value));
276 }
277 }
278 }
279 Ok(features)
280}
281
282#[cfg(feature = "unstable-v2")]
284fn nested_properties(layer: &ParsedLayer01<'_>) -> MltResult<Vec<Vec<(String, Value)>>> {
285 let mut features = vec![Vec::new(); layer.geometry_values().feature_count()];
286 for column in layer.nested() {
287 for (index, feature) in features.iter_mut().enumerate() {
288 feature.push((
289 column.name().to_string(),
290 nested_to_json(&column.row(index)?),
291 ));
292 }
293 }
294 Ok(features)
295}
296
297#[cfg(feature = "unstable-v2")]
299fn nested_to_json(value: &NestedValue) -> Value {
300 match value {
301 NestedValue::Leaf(leaf) => prop_to_json(leaf),
302 NestedValue::List(None) | NestedValue::Map(None) => Value::Null,
303 NestedValue::List(Some(items)) => Value::Array(items.iter().map(nested_to_json).collect()),
304 NestedValue::Map(Some(entries)) => Value::Object(
305 entries
306 .iter()
307 .map(|(key, value)| (key.clone(), nested_to_json(value)))
308 .collect(),
309 ),
310 }
311}
312
313#[cfg(feature = "unstable-v2")]
315fn prop_to_json(value: &crate::PropValue) -> Value {
316 use crate::PropValue as P;
317 match value {
318 P::Bool(v) => v.map_or(Value::Null, Value::Bool),
319 P::I8(v) => v.map_or(Value::Null, Value::from),
320 P::U8(v) => v.map_or(Value::Null, Value::from),
321 P::I32(v) => v.map_or(Value::Null, Value::from),
322 P::U32(v) => v.map_or(Value::Null, Value::from),
323 P::I64(v) => v.map_or(Value::Null, Value::from),
324 P::U64(v) => v.map_or(Value::Null, Value::from),
325 P::F32(v) => v.map_or(Value::Null, f32_to_json),
326 P::F64(v) => v.map_or(Value::Null, f64_to_json),
327 P::Str(v) => v.clone().map_or(Value::Null, Value::String),
328 }
329}
330
331#[cfg(feature = "unstable-v2")]
333fn m_value_to_json(values: &MValue) -> Option<Value> {
334 macro_rules! array {
336 ($values:expr, $to_json:expr) => {
337 Value::Array($values.iter().copied().map($to_json).collect())
338 };
339 }
340 Some(match values {
341 MValue::Bool(v) => array!(v.as_ref()?, Value::Bool),
342 MValue::I8(v) => array!(v.as_ref()?, Value::from),
343 MValue::U8(v) => array!(v.as_ref()?, Value::from),
344 MValue::I32(v) => array!(v.as_ref()?, Value::from),
345 MValue::U32(v) => array!(v.as_ref()?, Value::from),
346 MValue::I64(v) => array!(v.as_ref()?, Value::from),
347 MValue::U64(v) => array!(v.as_ref()?, Value::from),
348 MValue::F32(v) => array!(v.as_ref()?, f32_to_json),
349 MValue::F64(v) => array!(v.as_ref()?, f64_to_json),
350 MValue::Str(v) => Value::Array(
351 v.as_ref()?
352 .iter()
353 .map(|s| Value::String(s.clone()))
354 .collect(),
355 ),
356 })
357}
358
359impl From<PropValueRef<'_>> for Value {
360 fn from(v: PropValueRef<'_>) -> Self {
361 match v {
362 PropValueRef::Bool(v) => Self::Bool(v),
363 PropValueRef::I8(v) => Self::from(v),
364 PropValueRef::U8(v) => Self::from(v),
365 PropValueRef::I32(v) => Self::from(v),
366 PropValueRef::U32(v) => Self::from(v),
367 PropValueRef::I64(v) => Self::from(v),
368 PropValueRef::U64(v) => Self::from(v),
369 PropValueRef::F32(v) => f32_to_json(v),
370 PropValueRef::F64(v) => f64_to_json(v),
371 PropValueRef::Str(s) => Self::String(s.to_string()),
372 }
373 }
374}
375
376fn normalize_tiny_floats(value: Value) -> Value {
378 match value {
379 Value::Number(ref n) => {
380 let eps = f64::from(f32::EPSILON);
381 if let Some(f) = n.as_f64()
382 && f.is_finite()
383 && f.abs() < eps
384 {
385 Value::from(0.0)
386 } else {
387 value
388 }
389 }
390 Value::Array(arr) => Value::Array(arr.into_iter().map(normalize_tiny_floats).collect()),
391 Value::Object(obj) => Value::Object(
392 obj.into_iter()
393 .map(|(k, v)| (k, normalize_tiny_floats(v)))
394 .collect(),
395 ),
396 Value::Null | Value::Bool(_) | Value::String(_) => value,
397 }
398}
399
400fn json_values_equal(a: &Value, b: &Value) -> bool {
404 match (a, b) {
405 (Value::Number(na), Value::Number(nb)) if na.is_f64() && nb.is_f64() => {
406 let na = na.as_f64().expect("f64");
407 let nb = nb.as_f64().expect("f64");
408 assert!(
409 !na.is_nan() && !nb.is_nan(),
410 "unexpected non-finite numbers"
411 );
412 let abs_diff = (na - nb).abs();
413 let max_abs = na.abs().max(nb.abs()).max(1.0);
414 abs_diff <= f64::from(f32::EPSILON) * max_abs * 2.0
415 }
416 (Value::Array(aa), Value::Array(ab)) => {
417 aa.len() == ab.len()
418 && aa
419 .iter()
420 .zip(ab.iter())
421 .all(|(x, y)| json_values_equal(x, y))
422 }
423 (Value::Object(ao), Value::Object(bo)) => {
424 ao.len() == bo.len()
425 && ao
426 .iter()
427 .all(|(k, v)| bo.get(k).is_some_and(|w| json_values_equal(v, w)))
428 }
429 _ => a == b,
430 }
431}