Skip to main content

s2json_core/
lib.rs

1#![no_std]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6//! The `s2json` Rust crate provides functionalities to read and write S2JSON Spec data structures.
7//! This crate is a 0 dependency package that uses `no_std` and is intended to be used in
8//! embedded systems and WASM applications.
9//!
10//! NOTE: WG stands for WGS84 and S2 stands for S2Geometry
11
12extern crate alloc;
13
14/// All geometry types and structs
15pub mod geometry;
16/// All json, value, shape impl
17pub mod impls;
18/// BTreeMap wrapper
19pub mod map;
20/// All shape types and structs
21pub mod shape;
22/// All values types and structs
23pub mod value;
24
25use alloc::{collections::BTreeSet, string::String, vec::Vec};
26pub use geometry::*;
27pub use impls::*;
28pub use map::*;
29use serde::{Deserialize, Serialize};
30pub use shape::*;
31pub use value::*;
32
33/// All projections that can be used
34#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
35pub enum Projection {
36    /// S2
37    #[default]
38    S2,
39    /// WG
40    WG,
41}
42
43//? S2 specific type
44
45/// Cube-face on the S2 sphere. Includes the WebMercator face incase datasets support both projections
46#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
47pub enum Face {
48    /// Face 0
49    #[default]
50    Face0 = 0,
51    /// Face 1
52    Face1 = 1,
53    /// Face 2
54    Face2 = 2,
55    /// Face 3
56    Face3 = 3,
57    /// Face 4
58    Face4 = 4,
59    /// Face 5
60    Face5 = 5,
61    /// WebMercator (WM) Face
62    WM = 6,
63}
64impl From<Face> for u8 {
65    fn from(face: Face) -> Self {
66        face as u8
67    }
68}
69impl From<u8> for Face {
70    fn from(face: u8) -> Self {
71        match face {
72            1 => Face::Face1,
73            2 => Face::Face2,
74            3 => Face::Face3,
75            4 => Face::Face4,
76            5 => Face::Face5,
77            6 => Face::WM,
78            _ => Face::Face0,
79        }
80    }
81}
82impl serde::Serialize for Face {
83    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84    where
85        S: serde::Serializer,
86    {
87        serializer.serialize_u8(*self as u8)
88    }
89}
90
91impl<'de> serde::Deserialize<'de> for Face {
92    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
93    where
94        D: serde::Deserializer<'de>,
95    {
96        let value = u8::deserialize(deserializer)?;
97        match value {
98            0 => Ok(Face::Face0),
99            1 => Ok(Face::Face1),
100            2 => Ok(Face::Face2),
101            3 => Ok(Face::Face3),
102            4 => Ok(Face::Face4),
103            5 => Ok(Face::Face5),
104            6 => Ok(Face::WM),
105            _ => Err(serde::de::Error::custom("Invalid face value")),
106        }
107    }
108}
109
110/// FeatureCollection type string
111#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
112pub enum FeatureCollectionType {
113    /// WG FeatureCollection
114    #[default]
115    FeatureCollection,
116}
117impl From<&str> for FeatureCollectionType {
118    fn from(_: &str) -> Self {
119        FeatureCollectionType::FeatureCollection
120    }
121}
122
123/// FeatureCollection type string
124#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
125pub enum S2FeatureCollectionType {
126    /// WG FeatureCollection
127    #[default]
128    S2FeatureCollection,
129}
130impl From<&str> for S2FeatureCollectionType {
131    fn from(_: &str) -> Self {
132        S2FeatureCollectionType::S2FeatureCollection
133    }
134}
135
136//? FeatureCollections
137
138/// WG FeatureCollection
139#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
140pub struct FeatureCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
141    /// Type will always be "FeatureCollection"
142    #[serde(rename = "type")]
143    pub _type: FeatureCollectionType,
144    /// Collection of WG features
145    pub features: Vec<Features<M, P, D>>,
146    /// Attribution data
147    #[serde(skip_serializing_if = "Option::is_none")]
148    pub attributions: Option<Attributions>,
149    /// Bounding box
150    #[serde(skip_serializing_if = "Option::is_none")]
151    pub bbox: Option<BBox>,
152}
153impl<M, P: Clone + Default, D: Clone + Default> FeatureCollection<M, P, D> {
154    /// Create a new FeatureCollection
155    pub fn new(attributions: Option<Attributions>) -> Self {
156        Self { _type: "FeatureCollection".into(), features: Vec::new(), attributions, bbox: None }
157    }
158
159    /// update the bounding box
160    pub fn update_bbox(&mut self, bbox: BBox) {
161        let mut self_bbox = self.bbox.unwrap_or_default();
162        self_bbox = self_bbox.merge(&bbox);
163        self.bbox = Some(self_bbox);
164    }
165}
166impl<M, P: Clone + Default, D: Clone + Default> From<Vec<VectorFeature<M, P, D>>>
167    for FeatureCollection<M, P, D>
168{
169    fn from(mut features: Vec<VectorFeature<M, P, D>>) -> Self {
170        let mut bbox = BBox::default();
171        for feature in features.iter_mut() {
172            bbox.merge_in_place(&BBox::from(feature.geometry.bbox()));
173        }
174        Self {
175            _type: FeatureCollectionType::FeatureCollection,
176            features: features.into_iter().map(Features::VectorFeature).collect(),
177            attributions: None,
178            bbox: Some(bbox),
179        }
180    }
181}
182impl<M, P: Clone + Default, D: Clone + Default> From<Vec<Feature<M, P, D>>>
183    for FeatureCollection<M, P, D>
184{
185    fn from(mut features: Vec<Feature<M, P, D>>) -> Self {
186        let mut bbox: BBox = BBox::default();
187        for feature in features.iter_mut() {
188            bbox.merge_in_place(&BBox::from(feature.geometry.bbox()));
189        }
190        Self {
191            _type: FeatureCollectionType::FeatureCollection,
192            features: features.into_iter().map(Features::Feature).collect(),
193            attributions: None,
194            bbox: Some(bbox),
195        }
196    }
197}
198impl<M, P: Clone + Default, D: Clone + Default> From<Vec<Features<M, P, D>>>
199    for FeatureCollection<M, P, D>
200{
201    fn from(mut features: Vec<Features<M, P, D>>) -> Self {
202        let mut bbox: BBox = BBox::default();
203        for feature in features.iter_mut() {
204            match feature {
205                Features::Feature(f) => {
206                    bbox.merge_in_place(&BBox::from(f.geometry.bbox()));
207                }
208                Features::VectorFeature(f) => {
209                    bbox.merge_in_place(&BBox::from(f.geometry.bbox()));
210                }
211            }
212        }
213        Self {
214            _type: FeatureCollectionType::FeatureCollection,
215            features,
216            attributions: None,
217            bbox: Some(bbox),
218        }
219    }
220}
221
222/// S2 FeatureCollection
223#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
224pub struct S2FeatureCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue>
225{
226    /// Type will always be "S2FeatureCollection"
227    #[serde(rename = "type")]
228    pub _type: S2FeatureCollectionType,
229    /// Collection of S2 features
230    pub features: Vec<VectorFeature<M, P, D>>,
231    /// Track the faces that were used to generate the features
232    pub faces: Vec<Face>,
233    /// Attribution data
234    #[serde(skip_serializing_if = "Option::is_none")]
235    pub attributions: Option<Attributions>,
236    /// Bounding box
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub bbox: Option<BBox>,
239}
240impl<M, P: Clone + Default, D: Clone + Default> S2FeatureCollection<M, P, D> {
241    /// Create a new S2FeatureCollection
242    pub fn new(attributions: Option<Attributions>) -> Self {
243        Self {
244            _type: "S2FeatureCollection".into(),
245            features: Vec::new(),
246            faces: Vec::new(),
247            attributions,
248            bbox: None,
249        }
250    }
251
252    /// update the bounding box
253    pub fn update_bbox(&mut self, bbox: BBox) {
254        let mut self_bbox = self.bbox.unwrap_or_default();
255        self_bbox = self_bbox.merge(&bbox);
256        self.bbox = Some(self_bbox);
257    }
258
259    /// Add a face, ensuring it is unique
260    pub fn add_face(&mut self, face: Face) {
261        if !self.faces.contains(&face) {
262            self.faces.push(face);
263        }
264    }
265}
266impl<M, P: Clone + Default, D: Clone + Default> From<Vec<VectorFeature<M, P, D>>>
267    for S2FeatureCollection<M, P, D>
268{
269    fn from(mut features: Vec<VectorFeature<M, P, D>>) -> Self {
270        let mut bbox = BBox::default();
271        let mut faces: BTreeSet<Face> = BTreeSet::new();
272        for feature in features.iter_mut() {
273            bbox.merge_in_place(&BBox::from(feature.geometry.bbox()));
274            faces.insert(feature.face);
275        }
276        Self {
277            _type: S2FeatureCollectionType::S2FeatureCollection,
278            features,
279            attributions: None,
280            faces: faces.into_iter().collect(),
281            bbox: Some(bbox),
282        }
283    }
284}
285
286//? Features
287
288/// Feature type string
289#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
290pub enum FeatureType {
291    /// WG Feature
292    #[default]
293    Feature,
294}
295impl From<&str> for FeatureType {
296    fn from(_: &str) -> Self {
297        FeatureType::Feature
298    }
299}
300
301/// Component to build an WG Feature
302#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
303pub struct Feature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
304    /// Type will always be "Feature"
305    #[serde(rename = "type")]
306    pub _type: FeatureType,
307    /// Unique identifier
308    #[serde(skip_serializing_if = "Option::is_none")]
309    pub id: Option<u64>,
310    /// Properties of the feature
311    #[serde(default)]
312    pub properties: P,
313    /// Geometry of the feature
314    pub geometry: Geometry<D>,
315    /// Metadata of the feature
316    #[serde(skip_serializing_if = "Option::is_none")]
317    pub metadata: Option<M>,
318}
319impl<M, P: Clone + Default, D: Clone + Default> Feature<M, P, D> {
320    /// Create a new Feature
321    pub fn new(id: Option<u64>, properties: P, geometry: Geometry<D>, metadata: Option<M>) -> Self {
322        Self { _type: "Feature".into(), id, properties, geometry, metadata }
323    }
324}
325impl<M, P: Clone + Default, D: Clone + Default> Default for Feature<M, P, D> {
326    fn default() -> Self {
327        Self {
328            _type: "Feature".into(),
329            id: None,
330            properties: Default::default(),
331            geometry: Default::default(),
332            metadata: None,
333        }
334    }
335}
336
337/// Feature type string
338#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
339pub enum VectorFeatureType {
340    /// WG Feature
341    #[default]
342    VectorFeature,
343    /// S2 Feature
344    S2Feature,
345}
346impl From<&str> for VectorFeatureType {
347    fn from(s: &str) -> Self {
348        match s {
349            "S2Feature" => VectorFeatureType::S2Feature,
350            _ => VectorFeatureType::VectorFeature,
351        }
352    }
353}
354
355/// Component to build an WG or S2 Vector Feature
356#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
357pub struct VectorFeature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
358    /// Type will always be "VectorFeature"
359    #[serde(rename = "type")]
360    pub _type: VectorFeatureType,
361    /// Unique identifier
362    #[serde(skip_serializing_if = "Option::is_none")]
363    pub id: Option<u64>,
364    /// Face of the feature
365    #[serde(default)]
366    pub face: Face,
367    /// Properties of the feature
368    #[serde(default)]
369    pub properties: P,
370    /// Geometry of the feature
371    pub geometry: VectorGeometry<D>,
372    /// Metadata of the feature
373    #[serde(skip_serializing_if = "Option::is_none")]
374    pub metadata: Option<M>,
375}
376impl<M, P: Clone + Default, D: Clone + Default> Default for VectorFeature<M, P, D> {
377    fn default() -> Self {
378        Self {
379            _type: "VectorFeature".into(),
380            face: Face::WM,
381            id: None,
382            properties: Default::default(),
383            geometry: Default::default(),
384            metadata: None,
385        }
386    }
387}
388impl<M, P: Clone + Default, D: Clone + Default> VectorFeature<M, P, D> {
389    /// Create a new VectorFeature in the WG/WM format
390    pub fn new_wm(
391        id: Option<u64>,
392        properties: P,
393        geometry: VectorGeometry<D>,
394        metadata: Option<M>,
395    ) -> Self {
396        Self { _type: "VectorFeature".into(), face: Face::WM, id, properties, geometry, metadata }
397    }
398
399    /// Create a new VectorFeature in the S2 format
400    pub fn new_s2(
401        id: Option<u64>,
402        face: Face,
403        properties: P,
404        geometry: VectorGeometry<D>,
405        metadata: Option<M>,
406    ) -> Self {
407        Self { _type: "S2Feature".into(), face, id, properties, geometry, metadata }
408    }
409
410    /// Create a new VectorFeature using an input VectorFeature. Assign new geometry if provided
411    pub fn from_vector_feature(
412        feature: &VectorFeature<M, P, D>,
413        geometry: Option<VectorGeometry<D>>,
414    ) -> Self
415    where
416        M: Clone,
417    {
418        Self {
419            _type: feature._type.clone(),
420            id: feature.id,
421            face: feature.face,
422            properties: feature.properties.clone(),
423            geometry: geometry.unwrap_or(feature.geometry.clone()),
424            metadata: feature.metadata.clone(),
425        }
426    }
427
428    /// Create a VectorFeature that set's properties and geometry to m-values.
429    /// Update the metadata to user defined value
430    pub fn to_m_vector_feature<M2>(
431        &self,
432        to_meta: impl FnOnce(Option<&M>) -> Option<M2>,
433    ) -> VectorFeature<M2, Properties, MValue>
434    where
435        M: Clone,
436        P: MValueCompatible,
437        D: MValueCompatible,
438    {
439        VectorFeature {
440            _type: self._type.clone(),
441            id: self.id,
442            face: self.face,
443            properties: self.properties.clone().into(),
444            geometry: self.geometry.to_m_geometry(),
445            metadata: to_meta(self.metadata.as_ref()),
446        }
447    }
448}
449
450//? Utility types
451
452/// Attribution data is stored in an object.
453/// The key is the name of the attribution, and the value is the href link
454/// e.g. { "Open S2": "https://opens2.com/legal/data" }
455pub type Attributions = Map<String, String>;
456
457/// Either an S2 or WG FeatureCollection
458#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
459#[serde(untagged)]
460pub enum FeatureCollections<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
461    /// An WG FeatureCollection
462    FeatureCollection(FeatureCollection<M, P, D>),
463    /// An S2 FeatureCollection
464    S2FeatureCollection(S2FeatureCollection<M, P, D>),
465}
466impl<M, P: Clone + Default, D: Clone + Default> From<FeatureCollection<M, P, D>>
467    for FeatureCollections<M, P, D>
468{
469    fn from(f: FeatureCollection<M, P, D>) -> Self {
470        FeatureCollections::FeatureCollection(f)
471    }
472}
473impl<M, P: Clone + Default, D: Clone + Default> From<S2FeatureCollection<M, P, D>>
474    for FeatureCollections<M, P, D>
475{
476    fn from(f: S2FeatureCollection<M, P, D>) -> Self {
477        FeatureCollections::S2FeatureCollection(f)
478    }
479}
480
481/// Either an S2, Vector WG or WG Feature
482#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
483#[serde(untagged)]
484pub enum Features<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
485    /// An WG Feature
486    Feature(Feature<M, P, D>),
487    /// An WG or S2 Vector Feature
488    VectorFeature(VectorFeature<M, P, D>),
489}
490impl<M, P: Clone + Default, D: Clone + Default> From<Feature<M, P, D>> for Features<M, P, D> {
491    fn from(f: Feature<M, P, D>) -> Self {
492        Features::Feature(f)
493    }
494}
495impl<M, P: Clone + Default, D: Clone + Default> From<VectorFeature<M, P, D>> for Features<M, P, D> {
496    fn from(f: VectorFeature<M, P, D>) -> Self {
497        Features::VectorFeature(f)
498    }
499}
500
501/// All major GeoJSON and S2JSON types
502#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
503#[serde(untagged)]
504pub enum JSONCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
505    /// An WG FeatureCollection
506    FeatureCollection(FeatureCollection<M, P, D>),
507    /// An S2 FeatureCollection
508    S2FeatureCollection(S2FeatureCollection<M, P, D>),
509    /// An WG Feature
510    Feature(Feature<M, P, D>),
511    /// An WG Vector Feature
512    VectorFeature(VectorFeature<M, P, D>),
513}
514impl<M, P: Clone + Default, D: Clone + Default> From<FeatureCollection<M, P, D>>
515    for JSONCollection<M, P, D>
516{
517    fn from(f: FeatureCollection<M, P, D>) -> Self {
518        JSONCollection::FeatureCollection(f)
519    }
520}
521impl<M, P: Clone + Default, D: Clone + Default> From<S2FeatureCollection<M, P, D>>
522    for JSONCollection<M, P, D>
523{
524    fn from(f: S2FeatureCollection<M, P, D>) -> Self {
525        JSONCollection::S2FeatureCollection(f)
526    }
527}
528impl<M, P: Clone + Default, D: Clone + Default> From<Feature<M, P, D>> for JSONCollection<M, P, D> {
529    fn from(f: Feature<M, P, D>) -> Self {
530        JSONCollection::Feature(f)
531    }
532}
533impl<M, P: Clone + Default, D: Clone + Default> From<VectorFeature<M, P, D>>
534    for JSONCollection<M, P, D>
535{
536    fn from(f: VectorFeature<M, P, D>) -> Self {
537        JSONCollection::VectorFeature(f)
538    }
539}