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