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::{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}
166
167/// S2 FeatureCollection
168#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
169pub struct S2FeatureCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue>
170{
171    /// Type will always be "S2FeatureCollection"
172    #[serde(rename = "type")]
173    pub _type: S2FeatureCollectionType,
174    /// Collection of S2 features
175    pub features: Vec<VectorFeature<M, P, D>>,
176    /// Track the faces that were used to generate the features
177    pub faces: Vec<Face>,
178    /// Attribution data
179    #[serde(skip_serializing_if = "Option::is_none")]
180    pub attributions: Option<Attributions>,
181    /// Bounding box
182    #[serde(skip_serializing_if = "Option::is_none")]
183    pub bbox: Option<BBox>,
184}
185impl<M, P: Clone + Default, D: Clone + Default> S2FeatureCollection<M, P, D> {
186    /// Create a new S2FeatureCollection
187    pub fn new(attributions: Option<Attributions>) -> Self {
188        Self {
189            _type: "S2FeatureCollection".into(),
190            features: Vec::new(),
191            faces: Vec::new(),
192            attributions,
193            bbox: None,
194        }
195    }
196
197    /// update the bounding box
198    pub fn update_bbox(&mut self, bbox: BBox) {
199        let mut self_bbox = self.bbox.unwrap_or_default();
200        self_bbox = self_bbox.merge(&bbox);
201        self.bbox = Some(self_bbox);
202    }
203
204    /// Add a face, ensuring it is unique
205    pub fn add_face(&mut self, face: Face) {
206        if !self.faces.contains(&face) {
207            self.faces.push(face);
208        }
209    }
210}
211
212//? Features
213
214/// Feature type string
215#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
216pub enum FeatureType {
217    /// WG Feature
218    #[default]
219    Feature,
220}
221impl From<&str> for FeatureType {
222    fn from(_: &str) -> Self {
223        FeatureType::Feature
224    }
225}
226
227/// Component to build an WG Feature
228#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
229pub struct Feature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
230    /// Type will always be "Feature"
231    #[serde(rename = "type")]
232    pub _type: FeatureType,
233    /// Unique identifier
234    #[serde(skip_serializing_if = "Option::is_none")]
235    pub id: Option<u64>,
236    /// Properties of the feature
237    #[serde(default)]
238    pub properties: P,
239    /// Geometry of the feature
240    pub geometry: Geometry<D>,
241    /// Metadata of the feature
242    #[serde(skip_serializing_if = "Option::is_none")]
243    pub metadata: Option<M>,
244}
245impl<M, P: Clone + Default, D: Clone + Default> Feature<M, P, D> {
246    /// Create a new Feature
247    pub fn new(id: Option<u64>, properties: P, geometry: Geometry<D>, metadata: Option<M>) -> Self {
248        Self { _type: "Feature".into(), id, properties, geometry, metadata }
249    }
250}
251impl<M, P: Clone + Default, D: Clone + Default> Default for Feature<M, P, D> {
252    fn default() -> Self {
253        Self {
254            _type: "Feature".into(),
255            id: None,
256            properties: Default::default(),
257            geometry: Default::default(),
258            metadata: None,
259        }
260    }
261}
262
263/// Feature type string
264#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
265pub enum VectorFeatureType {
266    /// WG Feature
267    #[default]
268    VectorFeature,
269    /// S2 Feature
270    S2Feature,
271}
272impl From<&str> for VectorFeatureType {
273    fn from(s: &str) -> Self {
274        match s {
275            "S2Feature" => VectorFeatureType::S2Feature,
276            _ => VectorFeatureType::VectorFeature,
277        }
278    }
279}
280
281/// Component to build an WG or S2 Vector Feature
282#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
283pub struct VectorFeature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
284    /// Type will always be "VectorFeature"
285    #[serde(rename = "type")]
286    pub _type: VectorFeatureType,
287    /// Unique identifier
288    #[serde(skip_serializing_if = "Option::is_none")]
289    pub id: Option<u64>,
290    /// Face of the feature
291    #[serde(default)]
292    pub face: Face,
293    /// Properties of the feature
294    #[serde(default)]
295    pub properties: P,
296    /// Geometry of the feature
297    pub geometry: VectorGeometry<D>,
298    /// Metadata of the feature
299    #[serde(skip_serializing_if = "Option::is_none")]
300    pub metadata: Option<M>,
301}
302impl<M, P: Clone + Default, D: Clone + Default> Default for VectorFeature<M, P, D> {
303    fn default() -> Self {
304        Self {
305            _type: "VectorFeature".into(),
306            face: 0.into(),
307            id: None,
308            properties: Default::default(),
309            geometry: Default::default(),
310            metadata: None,
311        }
312    }
313}
314impl<M, P: Clone + Default, D: Clone + Default> VectorFeature<M, P, D> {
315    /// Create a new VectorFeature in the WG/WM format
316    pub fn new_wm(
317        id: Option<u64>,
318        properties: P,
319        geometry: VectorGeometry<D>,
320        metadata: Option<M>,
321    ) -> Self {
322        Self { _type: "VectorFeature".into(), face: Face::WM, id, properties, geometry, metadata }
323    }
324
325    /// Create a new VectorFeature in the S2 format
326    pub fn new_s2(
327        id: Option<u64>,
328        face: Face,
329        properties: P,
330        geometry: VectorGeometry<D>,
331        metadata: Option<M>,
332    ) -> Self {
333        Self { _type: "S2Feature".into(), face, id, properties, geometry, metadata }
334    }
335
336    /// Create a new VectorFeature using an input VectorFeature. Assign new geometry if provided
337    pub fn from_vector_feature(
338        feature: &VectorFeature<M, P, D>,
339        geometry: Option<VectorGeometry<D>>,
340    ) -> Self
341    where
342        M: Clone,
343    {
344        Self {
345            _type: feature._type.clone(),
346            id: feature.id,
347            face: feature.face,
348            properties: feature.properties.clone(),
349            geometry: geometry.unwrap_or(feature.geometry.clone()),
350            metadata: feature.metadata.clone(),
351        }
352    }
353
354    /// Create a VectorFeature that set's properties and geometry to m-values.
355    /// Update the metadata to user defined value
356    pub fn to_m_vector_feature<M2>(
357        &self,
358        to_meta: impl FnOnce(Option<&M>) -> Option<M2>,
359    ) -> VectorFeature<M2, Properties, MValue>
360    where
361        M: Clone,
362        P: MValueCompatible,
363        D: MValueCompatible,
364    {
365        VectorFeature {
366            _type: self._type.clone(),
367            id: self.id,
368            face: self.face,
369            properties: self.properties.clone().into(),
370            geometry: self.geometry.to_m_geometry(),
371            metadata: to_meta(self.metadata.as_ref()),
372        }
373    }
374}
375
376//? Utility types
377
378/// Attribution data is stored in an object.
379/// The key is the name of the attribution, and the value is the href link
380/// e.g. { "Open S2": "https://opens2.com/legal/data" }
381pub type Attributions = Map<String, String>;
382
383/// Either an S2 or WG FeatureCollection
384#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
385#[serde(untagged)]
386pub enum FeatureCollections<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
387    /// An WG FeatureCollection
388    FeatureCollection(FeatureCollection<M, P, D>),
389    /// An S2 FeatureCollection
390    S2FeatureCollection(S2FeatureCollection<M, P, D>),
391}
392
393/// Either an S2, Vector WG or WG Feature
394#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
395#[serde(untagged)]
396pub enum Features<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
397    /// An WG Feature
398    Feature(Feature<M, P, D>),
399    /// An WG or S2 Vector Feature
400    VectorFeature(VectorFeature<M, P, D>),
401}
402
403/// All major GeoJSON and S2JSON types
404#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
405#[serde(untagged)]
406pub enum JSONCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
407    /// An WG FeatureCollection
408    FeatureCollection(FeatureCollection<M, P, D>),
409    /// An S2 FeatureCollection
410    S2FeatureCollection(S2FeatureCollection<M, P, D>),
411    /// An WG Feature
412    Feature(Feature<M, P, D>),
413    /// An WG Vector Feature
414    VectorFeature(VectorFeature<M, P, D>),
415}