s2json_core/
lib.rs

1#![no_std]
2#![feature(coverage_attribute)]
3#![deny(missing_docs)]
4
5//! The `s2json` Rust crate provides functionalities to read and write S2JSON Spec data structures.
6//! This crate is a 0 dependency package that uses `no_std` and is intended to be used in
7//! embedded systems and WASM applications.
8//! NOTE: WM stands for WGS84 and S2 stands for S2Geometry
9
10extern crate alloc;
11
12/// All geometry types and structs
13pub mod geometry;
14/// BTreeMap wrapper
15pub mod map;
16/// All values types and structs
17pub mod value;
18/// All values impl
19pub mod value_impl;
20/// The VectorPoint struct is a powerful tool for 2D and 3D points
21pub mod vector_point;
22
23use alloc::{string::String, vec::Vec};
24pub use geometry::*;
25pub use map::*;
26use serde::{Deserialize, Serialize};
27pub use value::*;
28pub use vector_point::*;
29
30/// All projections that can be used
31#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
32pub enum Projection {
33    /// S2
34    #[default]
35    S2,
36    /// WG
37    WG,
38}
39
40//? S2 specific type
41
42/// Cube-face on the S2 sphere
43#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
44pub enum Face {
45    /// Face 0
46    #[default]
47    Face0 = 0,
48    /// Face 1
49    Face1 = 1,
50    /// Face 2
51    Face2 = 2,
52    /// Face 3
53    Face3 = 3,
54    /// Face 4
55    Face4 = 4,
56    /// Face 5
57    Face5 = 5,
58}
59impl From<Face> for u8 {
60    fn from(face: Face) -> Self {
61        face as u8
62    }
63}
64impl From<u8> for Face {
65    fn from(face: u8) -> Self {
66        match face {
67            1 => Face::Face1,
68            2 => Face::Face2,
69            3 => Face::Face3,
70            4 => Face::Face4,
71            5 => Face::Face5,
72            _ => Face::Face0,
73        }
74    }
75}
76impl serde::Serialize for Face {
77    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
78    where
79        S: serde::Serializer,
80    {
81        serializer.serialize_u8(*self as u8)
82    }
83}
84
85impl<'de> serde::Deserialize<'de> for Face {
86    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
87    where
88        D: serde::Deserializer<'de>,
89    {
90        let value = u8::deserialize(deserializer)?;
91        match value {
92            0 => Ok(Face::Face0),
93            1 => Ok(Face::Face1),
94            2 => Ok(Face::Face2),
95            3 => Ok(Face::Face3),
96            4 => Ok(Face::Face4),
97            5 => Ok(Face::Face5),
98            _ => Err(serde::de::Error::custom("Invalid face value")),
99        }
100    }
101}
102
103/// FeatureCollection type string
104#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
105pub enum FeatureCollectionType {
106    /// WM FeatureCollection
107    #[default]
108    FeatureCollection,
109}
110impl From<&str> for FeatureCollectionType {
111    fn from(_: &str) -> Self {
112        FeatureCollectionType::FeatureCollection
113    }
114}
115
116/// FeatureCollection type string
117#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
118pub enum S2FeatureCollectionType {
119    /// WM FeatureCollection
120    #[default]
121    S2FeatureCollection,
122}
123impl From<&str> for S2FeatureCollectionType {
124    fn from(_: &str) -> Self {
125        S2FeatureCollectionType::S2FeatureCollection
126    }
127}
128
129//? FeatureCollections
130
131/// WM FeatureCollection
132#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
133pub struct FeatureCollection<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue>
134{
135    /// Type will always be "FeatureCollection"
136    #[serde(rename = "type")]
137    pub _type: FeatureCollectionType,
138    /// Collection of WM features
139    pub features: Vec<WMFeature<M, P, D>>,
140    /// Attribution data
141    #[serde(skip_serializing_if = "Option::is_none")]
142    pub attributions: Option<Attributions>,
143    /// Bounding box
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub bbox: Option<BBox>,
146}
147impl<M, P: MValueCompatible, D: MValueCompatible> FeatureCollection<M, P, D> {
148    /// Create a new FeatureCollection
149    pub fn new(attributions: Option<Attributions>) -> Self {
150        Self { _type: "FeatureCollection".into(), features: Vec::new(), attributions, bbox: None }
151    }
152
153    /// update the bounding box
154    pub fn update_bbox(&mut self, bbox: BBox) {
155        let mut self_bbox = self.bbox.unwrap_or_default();
156        self_bbox = self_bbox.merge(&bbox);
157        self.bbox = Some(self_bbox);
158    }
159}
160
161/// S2 FeatureCollection
162#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
163pub struct S2FeatureCollection<
164    M = (),
165    P: MValueCompatible = Properties,
166    D: MValueCompatible = MValue,
167> {
168    /// Type will always be "S2FeatureCollection"
169    #[serde(rename = "type")]
170    pub _type: S2FeatureCollectionType,
171    /// Collection of S2 features
172    pub features: Vec<VectorFeature<M, P, D>>,
173    /// Track the faces that were used to generate the features
174    pub faces: Vec<Face>,
175    /// Attribution data
176    #[serde(skip_serializing_if = "Option::is_none")]
177    pub attributions: Option<Attributions>,
178    /// Bounding box
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub bbox: Option<BBox>,
181}
182impl<M, P: MValueCompatible, D: MValueCompatible> S2FeatureCollection<M, P, D> {
183    /// Create a new S2FeatureCollection
184    pub fn new(attributions: Option<Attributions>) -> Self {
185        Self {
186            _type: "S2FeatureCollection".into(),
187            features: Vec::new(),
188            faces: Vec::new(),
189            attributions,
190            bbox: None,
191        }
192    }
193
194    /// update the bounding box
195    pub fn update_bbox(&mut self, bbox: BBox) {
196        let mut self_bbox = self.bbox.unwrap_or_default();
197        self_bbox = self_bbox.merge(&bbox);
198        self.bbox = Some(self_bbox);
199    }
200
201    /// Add a face, ensuring it is unique
202    pub fn add_face(&mut self, face: Face) {
203        if !self.faces.contains(&face) {
204            self.faces.push(face);
205        }
206    }
207}
208
209//? Features
210
211/// Feature type string
212#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
213pub enum FeatureType {
214    /// WM Feature
215    #[default]
216    Feature,
217}
218impl From<&str> for FeatureType {
219    fn from(_: &str) -> Self {
220        FeatureType::Feature
221    }
222}
223
224/// Component to build an WM Feature
225#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
226pub struct Feature<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue> {
227    /// Type will always be "Feature"
228    #[serde(rename = "type")]
229    pub _type: FeatureType,
230    /// Unique identifier
231    #[serde(skip_serializing_if = "Option::is_none")]
232    pub id: Option<u64>,
233    /// Properties of the feature
234    pub properties: P,
235    /// Geometry of the feature
236    pub geometry: Geometry<D>,
237    /// Metadata of the feature
238    #[serde(skip_serializing_if = "Option::is_none")]
239    pub metadata: Option<M>,
240}
241impl<M, P: MValueCompatible, D: MValueCompatible> Feature<M, P, D> {
242    /// Create a new Feature
243    pub fn new(id: Option<u64>, properties: P, geometry: Geometry<D>, metadata: Option<M>) -> Self {
244        Self { _type: "Feature".into(), id, properties, geometry, metadata }
245    }
246}
247impl<M, P: MValueCompatible, D: MValueCompatible> Default for Feature<M, P, D> {
248    fn default() -> Self {
249        Self {
250            _type: "Feature".into(),
251            id: None,
252            properties: Default::default(),
253            geometry: Default::default(),
254            metadata: None,
255        }
256    }
257}
258
259/// Feature type string
260#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
261pub enum VectorFeatureType {
262    /// WM Feature
263    #[default]
264    VectorFeature,
265    /// S2 Feature
266    S2Feature,
267}
268impl From<&str> for VectorFeatureType {
269    fn from(s: &str) -> Self {
270        match s {
271            "S2Feature" => VectorFeatureType::S2Feature,
272            _ => VectorFeatureType::VectorFeature,
273        }
274    }
275}
276
277/// Component to build an WM or S2 Vector Feature
278#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
279pub struct VectorFeature<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue> {
280    /// Type will always be "VectorFeature"
281    #[serde(rename = "type")]
282    pub _type: VectorFeatureType,
283    /// Unique identifier
284    #[serde(skip_serializing_if = "Option::is_none")]
285    pub id: Option<u64>,
286    /// Face of the feature
287    pub face: Face,
288    /// Properties of the feature
289    pub properties: P,
290    /// Geometry of the feature
291    pub geometry: VectorGeometry<D>,
292    /// Metadata of the feature
293    #[serde(skip_serializing_if = "Option::is_none")]
294    pub metadata: Option<M>,
295}
296impl<M, P: MValueCompatible, D: MValueCompatible> Default for VectorFeature<M, P, D> {
297    fn default() -> Self {
298        Self {
299            _type: "VectorFeature".into(),
300            face: 0.into(),
301            id: None,
302            properties: Default::default(),
303            geometry: Default::default(),
304            metadata: None,
305        }
306    }
307}
308impl<M, P: MValueCompatible, D: MValueCompatible> VectorFeature<M, P, D> {
309    /// Create a new VectorFeature in the WM format
310    pub fn new_wm(
311        id: Option<u64>,
312        properties: P,
313        geometry: VectorGeometry<D>,
314        metadata: Option<M>,
315    ) -> Self {
316        Self { _type: "VectorFeature".into(), face: 0.into(), id, properties, geometry, metadata }
317    }
318
319    /// Create a new VectorFeature in the WM format
320    pub fn new_s2(
321        id: Option<u64>,
322        face: Face,
323        properties: P,
324        geometry: VectorGeometry<D>,
325        metadata: Option<M>,
326    ) -> Self {
327        Self { _type: "S2Feature".into(), face, id, properties, geometry, metadata }
328    }
329
330    /// Create a new VectorFeature using an input VectorFeature. Assign new geometry if provided
331    pub fn from_vector_feature(
332        feature: &VectorFeature<M, P, D>,
333        geometry: Option<VectorGeometry<D>>,
334    ) -> Self
335    where
336        M: Clone,
337    {
338        Self {
339            _type: feature._type.clone(),
340            id: feature.id,
341            face: feature.face,
342            properties: feature.properties.clone(),
343            geometry: geometry.unwrap_or(feature.geometry.clone()),
344            metadata: feature.metadata.clone(),
345        }
346    }
347}
348
349//? Utility types
350
351/// Attribution data is stored in an object.
352/// The key is the name of the attribution, and the value is the href link
353/// e.g. { "Open S2": "https://opens2.com/legal/data" }
354pub type Attributions = Map<String, String>;
355
356/// Either an S2 or WM FeatureCollection
357#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
358pub enum FeatureCollections<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue>
359{
360    /// An WM FeatureCollection
361    FeatureCollection(FeatureCollection<M, P, D>),
362    /// An S2 FeatureCollection
363    S2FeatureCollection(S2FeatureCollection<M, P, D>),
364}
365
366/// Either an S2 or WM Feature
367#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
368pub enum Features<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue> {
369    /// An WM Feature
370    Feature(Feature<M, P, D>),
371    /// An WM or S2 Vector Feature
372    VectorFeature(VectorFeature<M, P, D>),
373}
374
375/// Either an WM Feature or an WM Vector Feature
376#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
377#[serde(untagged)]
378pub enum WMFeature<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue> {
379    /// An WM Feature
380    Feature(Feature<M, P, D>),
381    /// An WM Vector Feature
382    VectorFeature(VectorFeature<M, P, D>),
383}
384
385/// All major S2JSON types
386#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
387#[serde(untagged)]
388pub enum JSONCollection<M = (), P: MValueCompatible = Properties, D: MValueCompatible = MValue> {
389    /// An WM FeatureCollection
390    FeatureCollection(FeatureCollection<M, P, D>),
391    /// An S2 FeatureCollection
392    S2FeatureCollection(S2FeatureCollection<M, P, D>),
393    /// An WM Feature
394    Feature(Feature<M, P, D>),
395    /// An WM Vector Feature
396    VectorFeature(VectorFeature<M, P, D>),
397}
398
399#[cfg(test)]
400mod tests {
401    use super::*;
402    use alloc::{string::ToString, vec};
403
404    #[test]
405    fn face() {
406        let face = Face::Face0;
407        assert_eq!(u8::from(face), 0);
408        let face = Face::Face1;
409        assert_eq!(u8::from(face), 1);
410        let face = Face::Face2;
411        assert_eq!(u8::from(face), 2);
412        let face = Face::Face3;
413        assert_eq!(u8::from(face), 3);
414        let face = Face::Face4;
415        assert_eq!(u8::from(face), 4);
416        let face = Face::Face5;
417        assert_eq!(u8::from(face), 5);
418
419        assert_eq!(Face::Face0, Face::from(0));
420        assert_eq!(Face::Face1, Face::from(1));
421        assert_eq!(Face::Face2, Face::from(2));
422        assert_eq!(Face::Face3, Face::from(3));
423        assert_eq!(Face::Face4, Face::from(4));
424        assert_eq!(Face::Face5, Face::from(5));
425    }
426
427    #[test]
428    fn defaults() {
429        let f: Feature = Default::default();
430        assert_eq!(f._type, "Feature".into());
431        assert_eq!(f.id, None);
432        assert_eq!(f.properties, Properties::default());
433        assert_eq!(f.geometry, Geometry::default());
434        assert_eq!(f.metadata, None);
435
436        let f: VectorFeature = Default::default();
437        assert_eq!(f._type, "VectorFeature".into());
438        assert_eq!(f.id, None);
439        assert_eq!(f.face, 0.into());
440        assert_eq!(f.properties, Properties::default());
441        assert_eq!(f.geometry, VectorGeometry::default());
442        assert_eq!(f.metadata, None);
443    }
444
445    #[test]
446    fn feature_collection_new() {
447        let mut attributions = Attributions::new();
448        attributions.insert("Open S2".to_string(), "https://opens2.com/legal/data".to_string());
449        let mut fc = FeatureCollection::<()>::new(Some(attributions.clone()));
450        assert_eq!(fc._type, FeatureCollectionType::FeatureCollection);
451        assert_eq!(fc.features.len(), 0);
452        assert_eq!(fc.attributions, Some(attributions.clone()));
453        // update_bbox
454        fc.update_bbox(BBox::new(5., -2., 35., 2.2));
455        assert_eq!(fc.bbox, Some(BBox::new(5., -2., 35., 2.2)));
456
457        let string = serde_json::to_string(&fc).unwrap();
458        assert_eq!(string, "{\"type\":\"FeatureCollection\",\"features\":[],\"attributions\":{\"Open S2\":\"https://opens2.com/legal/data\"},\"bbox\":[5.0,-2.0,35.0,2.2]}");
459        let back_to_fc: FeatureCollection = serde_json::from_str(&string).unwrap();
460        assert_eq!(back_to_fc, fc);
461    }
462
463    #[test]
464    fn s2_feature_collection_new() {
465        let mut attributions = Attributions::new();
466        attributions.insert("Open S2".to_string(), "https://opens2.com/legal/data".to_string());
467        let mut fc = S2FeatureCollection::new(Some(attributions.clone()));
468        assert_eq!(fc._type, S2FeatureCollectionType::S2FeatureCollection);
469        assert_eq!(fc.features.len(), 0);
470        assert_eq!(fc.attributions, Some(attributions.clone()));
471        // update_bbox
472        fc.update_bbox(BBox::new(5., -2., 35., 2.2));
473        assert_eq!(fc.bbox, Some(BBox::new(5., -2., 35., 2.2)));
474        // add face
475        fc.add_face(0.into());
476        fc.add_face(3.into());
477        assert_eq!(fc.faces, vec![0.into(), 3.into()]);
478
479        let string = serde_json::to_string(&fc).unwrap();
480        assert_eq!(string, "{\"type\":\"S2FeatureCollection\",\"features\":[],\"faces\":[0,3],\"attributions\":{\"Open S2\":\"https://opens2.com/legal/data\"},\"bbox\":[5.0,-2.0,35.0,2.2]}");
481        let back_to_fc: S2FeatureCollection = serde_json::from_str(&string).unwrap();
482        assert_eq!(back_to_fc, fc);
483    }
484
485    #[test]
486    fn feature_new() {
487        let fc: Feature = Feature::new(
488            Some(22),
489            Properties::new(),
490            Geometry::Point(PointGeometry {
491                _type: "Point".into(),
492                coordinates: Point(0.0, 0.0),
493                m_values: None,
494                bbox: None,
495            }),
496            None,
497        );
498        assert_eq!(fc.id, Some(22));
499        assert_eq!(fc._type, "Feature".into());
500        assert_eq!(
501            fc.geometry,
502            Geometry::Point(PointGeometry {
503                _type: "Point".into(),
504                coordinates: Point(0.0, 0.0),
505                m_values: None,
506                bbox: None,
507            })
508        );
509        assert_eq!(fc.properties, Properties::new());
510        assert_eq!(fc.metadata, None);
511    }
512
513    #[test]
514    fn s2_feature_new() {
515        let fc: VectorFeature = VectorFeature::new_wm(
516            Some(55),
517            Properties::new(),
518            VectorGeometry::Point(VectorPointGeometry {
519                _type: "Point".into(),
520                coordinates: VectorPoint { x: 0.0, y: 1.0, z: Some(3.), m: None, t: None },
521                bbox: None,
522                is_3d: true,
523                offset: None,
524                vec_bbox: None,
525                indices: None,
526                tesselation: None,
527            }),
528            None,
529        );
530        assert_eq!(fc.id, Some(55));
531        assert_eq!(fc._type, "VectorFeature".into());
532        assert_eq!(
533            fc.geometry,
534            VectorGeometry::Point(VectorPointGeometry {
535                _type: "Point".into(),
536                coordinates: VectorPoint { x: 0.0, y: 1.0, z: Some(3.), m: None, t: None },
537                bbox: None,
538                is_3d: true,
539                offset: None,
540                vec_bbox: None,
541                indices: None,
542                tesselation: None,
543            })
544        );
545        assert_eq!(fc.properties, Properties::new());
546        assert_eq!(fc.metadata, None);
547        assert_eq!(fc.face, 0.into());
548
549        // S2
550
551        #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
552        struct MetaTest {
553            name: String,
554            value: String,
555        }
556
557        let fc = VectorFeature::<MetaTest>::new_s2(
558            Some(55),
559            3.into(),
560            Properties::new(),
561            VectorGeometry::Point(VectorPointGeometry {
562                _type: "Point".into(),
563                coordinates: VectorPoint { x: 0.0, y: 1.0, z: Some(3.), m: None, t: None },
564                bbox: None,
565                is_3d: true,
566                offset: None,
567                vec_bbox: None,
568                indices: None,
569                tesselation: None,
570            }),
571            Some(MetaTest { name: "test".to_string(), value: "value".to_string() }),
572        );
573        assert_eq!(fc.id, Some(55));
574        assert_eq!(fc._type, "S2Feature".into());
575        assert_eq!(
576            fc.geometry,
577            VectorGeometry::Point(VectorPointGeometry {
578                _type: "Point".into(),
579                coordinates: VectorPoint { x: 0.0, y: 1.0, z: Some(3.), m: None, t: None },
580                bbox: None,
581                is_3d: true,
582                offset: None,
583                vec_bbox: None,
584                indices: None,
585                tesselation: None,
586            })
587        );
588        assert_eq!(fc.properties, Properties::new());
589        assert_eq!(
590            fc.metadata,
591            Some(MetaTest { name: "test".to_string(), value: "value".to_string() })
592        );
593        assert_eq!(fc.face, 3.into());
594
595        let fc_to_str = serde_json::to_string(&fc).unwrap();
596        assert_eq!(
597            fc_to_str,
598            "{\"type\":\"S2Feature\",\"id\":55,\"face\":3,\"properties\":{},\"geometry\":{\"type\"\
599             :\"Point\",\"is3D\":true,\"coordinates\":{\"x\":0.0,\"y\":1.0,\"z\":3.0},\"indices\":\
600             null,\"tesselation\":null},\"metadata\":{\"name\":\"test\",\"value\":\"value\"}}"
601        );
602
603        // from_vector_feature
604
605        let new_geo = VectorGeometry::Point(VectorPointGeometry {
606            _type: "Point".into(),
607            coordinates: VectorPoint { x: 5.0, y: 4.0, z: Some(-3.), m: None, t: None },
608            bbox: None,
609            is_3d: true,
610            offset: None,
611            vec_bbox: None,
612            indices: None,
613            tesselation: None,
614        });
615        let fc_clone_new_geometry =
616            VectorFeature::<MetaTest>::from_vector_feature(&fc, Some(new_geo.clone()));
617
618        assert_eq!(fc_clone_new_geometry.geometry, new_geo);
619    }
620
621    #[test]
622    fn parse_feature_multipoint() {
623        let json_string = r#"{
624            "type": "Feature",
625            "properties": {},
626            "geometry": {
627                "type": "MultiPoint",
628                "coordinates": [
629                    [-13.292352825505162, 54.34883408204476],
630                    [36.83102287804303, 59.56941785818924],
631                    [50.34083898563978, 16.040052775278994],
632                    [76.38149901912357, 35.155968522292056]
633                ]
634            }
635        }"#;
636
637        let feature: Feature = serde_json::from_str(json_string).unwrap();
638        assert_eq!(feature._type, "Feature".into());
639        assert_eq!(
640            feature.geometry,
641            Geometry::MultiPoint(MultiPointGeometry {
642                _type: "MultiPoint".into(),
643                coordinates: vec![
644                    Point(-13.292352825505162, 54.34883408204476),
645                    Point(36.83102287804303, 59.56941785818924),
646                    Point(50.34083898563978, 16.040052775278994),
647                    Point(76.38149901912357, 35.155968522292056),
648                ],
649                ..Default::default()
650            })
651        );
652
653        let back_to_str = serde_json::to_string(&feature).unwrap();
654        assert_eq!(
655            back_to_str,
656            "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"MultiPoint\",\"\
657             coordinates\":[[-13.292352825505162,54.34883408204476],[36.83102287804303,59.\
658             56941785818924],[50.34083898563978,16.040052775278994],[76.38149901912357,35.\
659             155968522292056]]}}"
660        );
661    }
662
663    #[test]
664    fn parse_feature_linestring() {
665        let json_string = r#"{
666            "type": "Feature",
667            "properties": {},
668            "geometry": {
669                "type": "LineString",
670                "coordinates": [
671                    [-13.292352825505162, 54.34883408204476],
672                    [36.83102287804303, 59.56941785818924],
673                    [50.34083898563978, 16.040052775278994],
674                    [76.38149901912357, 35.155968522292056]
675                ]
676            }
677        }"#;
678
679        let feature: Feature = serde_json::from_str(json_string).unwrap();
680        assert_eq!(feature._type, "Feature".into());
681        assert_eq!(
682            feature.geometry,
683            Geometry::LineString(LineStringGeometry {
684                _type: "LineString".into(),
685                coordinates: vec![
686                    Point(-13.292352825505162, 54.34883408204476),
687                    Point(36.83102287804303, 59.56941785818924),
688                    Point(50.34083898563978, 16.040052775278994),
689                    Point(76.38149901912357, 35.155968522292056),
690                ],
691                ..Default::default()
692            })
693        );
694
695        let back_to_str = serde_json::to_string(&feature).unwrap();
696        assert_eq!(
697            back_to_str,
698            "{\"type\":\"Feature\",\"properties\":{},\"geometry\":{\"type\":\"LineString\",\"\
699             coordinates\":[[-13.292352825505162,54.34883408204476],[36.83102287804303,59.\
700             56941785818924],[50.34083898563978,16.040052775278994],[76.38149901912357,35.\
701             155968522292056]]}}"
702        );
703    }
704
705    #[test]
706    fn parse_vector_feature_linestring() {
707        let json_string = r#"{
708            "type": "VectorFeature",
709            "face": 0,
710            "properties": {},
711            "geometry": {
712                "type": "LineString",
713                "is3D": false,
714                "coordinates": [
715                    { "x": -13.292352825505162, "y": 54.34883408204476 },
716                    { "x": 36.83102287804303, "y": 59.56941785818924 },
717                    { "x": 50.34083898563978, "y": 16.040052775278994 },
718                    { "x": 76.38149901912357, "y": 35.155968522292056 }
719                ]
720            }
721        }"#;
722
723        let feature: VectorFeature = serde_json::from_str(json_string).unwrap();
724        assert_eq!(feature._type, "VectorFeature".into());
725        let geometry = feature.geometry;
726        assert_eq!(
727            geometry,
728            VectorGeometry::LineString(VectorLineStringGeometry {
729                _type: VectorGeometryType::LineString,
730                is_3d: false,
731                coordinates: vec![
732                    VectorPoint::from_xy(-13.292352825505162, 54.34883408204476),
733                    VectorPoint::from_xy(36.83102287804303, 59.56941785818924),
734                    VectorPoint::from_xy(50.34083898563978, 16.040052775278994),
735                    VectorPoint::from_xy(76.38149901912357, 35.155968522292056),
736                ],
737                ..Default::default()
738            })
739        )
740    }
741
742    #[test]
743    fn parse_vector_feature_multipoint() {
744        let json_string = r#"{
745            "type": "VectorFeature",
746            "face": 0,
747            "properties": {},
748            "geometry": {
749                "type": "MultiPoint",
750                "is3D": false,
751                "coordinates": [
752                    { "x": -13.292352825505162, "y": 54.34883408204476 },
753                    { "x": 36.83102287804303, "y": 59.56941785818924 },
754                    { "x": 50.34083898563978, "y": 16.040052775278994 },
755                    { "x": 76.38149901912357, "y": 35.155968522292056 }
756                ]
757            }
758        }"#;
759
760        let feature: VectorFeature = serde_json::from_str(json_string).unwrap();
761        assert_eq!(feature._type, "VectorFeature".into());
762        let geometry = feature.geometry;
763        assert_eq!(
764            geometry,
765            VectorGeometry::MultiPoint(VectorMultiPointGeometry {
766                _type: VectorGeometryType::MultiPoint,
767                is_3d: false,
768                coordinates: vec![
769                    VectorPoint::from_xy(-13.292352825505162, 54.34883408204476),
770                    VectorPoint::from_xy(36.83102287804303, 59.56941785818924),
771                    VectorPoint::from_xy(50.34083898563978, 16.040052775278994),
772                    VectorPoint::from_xy(76.38149901912357, 35.155968522292056),
773                ],
774                ..Default::default()
775            })
776        )
777    }
778
779    #[test]
780    fn serde_face() {
781        let face_0 = Face::Face0;
782        let serialized = serde_json::to_string(&face_0).unwrap();
783        assert_eq!(serialized, "0");
784        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
785        assert_eq!(deserialize, Face::Face0);
786
787        let face_1 = Face::Face1;
788        let serialized = serde_json::to_string(&face_1).unwrap();
789        assert_eq!(serialized, "1");
790        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
791        assert_eq!(deserialize, Face::Face1);
792
793        let face_2 = Face::Face2;
794        let serialized = serde_json::to_string(&face_2).unwrap();
795        assert_eq!(serialized, "2");
796        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
797        assert_eq!(deserialize, Face::Face2);
798
799        let face_3 = Face::Face3;
800        let serialized = serde_json::to_string(&face_3).unwrap();
801        assert_eq!(serialized, "3");
802        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
803        assert_eq!(deserialize, Face::Face3);
804
805        let face_4 = Face::Face4;
806        let serialized = serde_json::to_string(&face_4).unwrap();
807        assert_eq!(serialized, "4");
808        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
809        assert_eq!(deserialize, Face::Face4);
810
811        let face_5 = Face::Face5;
812        let serialized = serde_json::to_string(&face_5).unwrap();
813        assert_eq!(serialized, "5");
814        let deserialize = serde_json::from_str::<Face>(&serialized).unwrap();
815        assert_eq!(deserialize, Face::Face5);
816    }
817
818    #[test]
819    #[should_panic(expected = "Invalid face value")]
820    fn serde_face_err() {
821        let _ = serde_json::from_str::<Face>("6").unwrap();
822    }
823}