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::{Layer, 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 Layer::Tag01(parsed) = layer else {
29 continue;
30 };
31 let layer_name = parsed.name;
32 let extent = parsed.extent;
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,
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(skip_serializing_if = "Option::is_none")]
77 pub id: Option<u64>,
78 pub properties: BTreeMap<String, Value>,
79 #[serde(rename = "type")]
80 pub ty: String,
81}
82
83struct Geom32Wire<'a>(&'a Geometry<i32>);
84impl Serialize for Geom32Wire<'_> {
85 fn serialize<S: serde::Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
86 geom_serde::serialize(self.0, s)
87 }
88}
89
90impl Serialize for Feature {
92 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
93 let len = 3 + usize::from(self.id.is_some());
94 let mut map = serializer.serialize_map(Some(len))?;
95 map.serialize_entry("type", &self.ty)?;
96 if let Some(id) = self.id {
97 map.serialize_entry("id", &id)?;
98 }
99 map.serialize_entry("properties", &self.properties)?;
100 map.serialize_entry("geometry", &Geom32Wire(&self.geometry))?;
101 map.end()
102 }
103}
104
105mod geom_serde {
108 use geo_types::{
109 Geometry, LineString, MultiLineString, MultiPoint, MultiPolygon, Point, Polygon,
110 };
111 use serde::de::Error as _;
112 use serde::ser::{Error, SerializeMap as _};
113 use serde::{Deserialize, Deserializer, Serializer};
114 use serde_json::Value;
115
116 type Arr = [i32; 2];
117
118 fn ls_arr(ls: &LineString<i32>) -> Vec<Arr> {
119 ls.0.iter().copied().map(Into::into).collect()
120 }
121
122 fn poly_arr(poly: &Polygon<i32>) -> Vec<Vec<Arr>> {
123 std::iter::once(poly.exterior())
124 .chain(poly.interiors())
125 .map(ls_arr)
126 .collect()
127 }
128
129 fn arr_ls(v: Vec<Arr>) -> LineString<i32> {
130 LineString::from(v)
131 }
132
133 fn arr_poly(rings: Vec<Vec<Arr>>) -> Polygon<i32> {
134 let mut it = rings.into_iter();
135 let ext = it.next().map_or_else(|| LineString(vec![]), arr_ls);
136 Polygon::new(ext, it.map(arr_ls).collect())
137 }
138
139 pub fn serialize<S: Serializer>(g: &Geometry<i32>, s: S) -> Result<S::Ok, S::Error> {
140 let mut m = s.serialize_map(Some(2))?;
141 let (ty, coords): (&str, Value) = match g {
142 Geometry::Point(p) => ("Point", serde_json::to_value(Arr::from(*p)).unwrap()),
143 Geometry::LineString(ls) => ("LineString", serde_json::to_value(ls_arr(ls)).unwrap()),
144 Geometry::Polygon(poly) => ("Polygon", serde_json::to_value(poly_arr(poly)).unwrap()),
145 Geometry::MultiPoint(mp) => (
146 "MultiPoint",
147 serde_json::to_value(mp.0.iter().copied().map(Arr::from).collect::<Vec<_>>())
148 .unwrap(),
149 ),
150 Geometry::MultiLineString(mls) => (
151 "MultiLineString",
152 serde_json::to_value(mls.iter().map(ls_arr).collect::<Vec<_>>()).unwrap(),
153 ),
154 Geometry::MultiPolygon(mpoly) => (
155 "MultiPolygon",
156 serde_json::to_value(mpoly.iter().map(poly_arr).collect::<Vec<_>>()).unwrap(),
157 ),
158 _ => return Err(Error::custom("unsupported geometry variant")),
159 };
160 m.serialize_entry("type", ty)?;
161 m.serialize_entry("coordinates", &coords)?;
162 m.end()
163 }
164
165 pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Geometry<i32>, D::Error> {
166 fn parse<T: serde::de::DeserializeOwned, E: serde::de::Error>(v: Value) -> Result<T, E> {
167 serde_json::from_value(v).map_err(E::custom)
168 }
169
170 #[derive(Deserialize)]
171 struct Wire {
172 #[serde(rename = "type")]
173 ty: String,
174 coordinates: Value,
175 }
176
177 let Wire { ty, coordinates: c } = Wire::deserialize(d)?;
178 Ok(match ty.as_str() {
179 "Point" => Geometry::Point(Point::from(parse::<Arr, _>(c)?)),
180 "LineString" => Geometry::LineString(arr_ls(parse(c)?)),
181 "Polygon" => Geometry::Polygon(arr_poly(parse(c)?)),
182 "MultiPoint" => {
183 let v: Vec<Arr> = parse(c)?;
184 Geometry::MultiPoint(MultiPoint(v.into_iter().map(Point::from).collect()))
185 }
186 "MultiLineString" => {
187 let v: Vec<Vec<Arr>> = parse(c)?;
188 Geometry::MultiLineString(MultiLineString(v.into_iter().map(arr_ls).collect()))
189 }
190 "MultiPolygon" => {
191 let v: Vec<Vec<Vec<Arr>>> = parse(c)?;
192 Geometry::MultiPolygon(MultiPolygon(v.into_iter().map(arr_poly).collect()))
193 }
194 _ => {
195 return Err(D::Error::unknown_variant(
196 &ty,
197 &[
198 "Point",
199 "LineString",
200 "Polygon",
201 "MultiPoint",
202 "MultiLineString",
203 "MultiPolygon",
204 ],
205 ));
206 }
207 })
208 }
209}
210
211#[must_use]
213pub fn f32_to_json(f: f32) -> Value {
214 if f.is_nan() {
215 Value::String("f32::NAN".to_owned())
216 } else if f == f32::INFINITY {
217 Value::String("f32::INFINITY".to_owned())
218 } else if f == f32::NEG_INFINITY {
219 Value::String("f32::NEG_INFINITY".to_owned())
220 } else {
221 Number::from_f64(f64::from(f)).expect("finite f32").into()
222 }
223}
224
225#[must_use]
227pub fn f64_to_json(f: f64) -> Value {
228 if f.is_nan() {
229 Value::String("f64::NAN".to_owned())
230 } else if f == f64::INFINITY {
231 Value::String("f64::INFINITY".to_owned())
232 } else if f == f64::NEG_INFINITY {
233 Value::String("f64::NEG_INFINITY".to_owned())
234 } else {
235 Number::from_f64(f).expect("finite f64").into()
236 }
237}
238
239impl From<PropValueRef<'_>> for Value {
240 fn from(v: PropValueRef<'_>) -> Self {
241 match v {
242 PropValueRef::Bool(v) => Self::Bool(v),
243 PropValueRef::I8(v) => Self::from(v),
244 PropValueRef::U8(v) => Self::from(v),
245 PropValueRef::I32(v) => Self::from(v),
246 PropValueRef::U32(v) => Self::from(v),
247 PropValueRef::I64(v) => Self::from(v),
248 PropValueRef::U64(v) => Self::from(v),
249 PropValueRef::F32(v) => f32_to_json(v),
250 PropValueRef::F64(v) => f64_to_json(v),
251 PropValueRef::Str(s) => Self::String(s.to_string()),
252 }
253 }
254}
255
256fn normalize_tiny_floats(value: Value) -> Value {
258 match value {
259 Value::Number(ref n) => {
260 let eps = f64::from(f32::EPSILON);
261 if let Some(f) = n.as_f64()
262 && f.is_finite()
263 && f.abs() < eps
264 {
265 Value::from(0.0)
266 } else {
267 value
268 }
269 }
270 Value::Array(arr) => Value::Array(arr.into_iter().map(normalize_tiny_floats).collect()),
271 Value::Object(obj) => Value::Object(
272 obj.into_iter()
273 .map(|(k, v)| (k, normalize_tiny_floats(v)))
274 .collect(),
275 ),
276 v => v,
277 }
278}
279
280fn json_values_equal(a: &Value, b: &Value) -> bool {
284 match (a, b) {
285 (Value::Number(na), Value::Number(nb)) if na.is_f64() && nb.is_f64() => {
286 let na = na.as_f64().expect("f64");
287 let nb = nb.as_f64().expect("f64");
288 assert!(
289 !na.is_nan() && !nb.is_nan(),
290 "unexpected non-finite numbers"
291 );
292 let abs_diff = (na - nb).abs();
293 let max_abs = na.abs().max(nb.abs()).max(1.0);
294 abs_diff <= f64::from(f32::EPSILON) * max_abs * 2.0
295 }
296 (Value::Array(aa), Value::Array(ab)) => {
297 aa.len() == ab.len()
298 && aa
299 .iter()
300 .zip(ab.iter())
301 .all(|(x, y)| json_values_equal(x, y))
302 }
303 (Value::Object(ao), Value::Object(bo)) => {
304 ao.len() == bo.len()
305 && ao
306 .iter()
307 .all(|(k, v)| bo.get(k).is_some_and(|w| json_values_equal(v, w)))
308 }
309 _ => a == b,
310 }
311}