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//! NOTE: WG stands for WGS84 and S2 stands for S2Geometry
10
11extern crate alloc;
12
13/// All geometry types and structs
14pub mod geometry;
15/// All json, value, shape impl
16pub mod impls;
17/// BTreeMap wrapper
18pub mod map;
19/// All shape types and structs
20pub mod shape;
21/// All values types and structs
22pub mod value;
23
24use alloc::{string::String, vec::Vec};
25pub use geometry::*;
26pub use impls::*;
27pub use map::*;
28use serde::{Deserialize, Serialize};
29pub use shape::*;
30pub use value::*;
31
32/// All projections that can be used
33#[derive(Serialize, Deserialize, Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
34pub enum Projection {
35    /// S2
36    #[default]
37    S2,
38    /// WG
39    WG,
40}
41
42//? S2 specific type
43
44/// Cube-face on the S2 sphere
45#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default)]
46pub enum Face {
47    /// Face 0
48    #[default]
49    Face0 = 0,
50    /// Face 1
51    Face1 = 1,
52    /// Face 2
53    Face2 = 2,
54    /// Face 3
55    Face3 = 3,
56    /// Face 4
57    Face4 = 4,
58    /// Face 5
59    Face5 = 5,
60}
61impl From<Face> for u8 {
62    fn from(face: Face) -> Self {
63        face as u8
64    }
65}
66impl From<u8> for Face {
67    fn from(face: u8) -> Self {
68        match face {
69            1 => Face::Face1,
70            2 => Face::Face2,
71            3 => Face::Face3,
72            4 => Face::Face4,
73            5 => Face::Face5,
74            _ => Face::Face0,
75        }
76    }
77}
78impl serde::Serialize for Face {
79    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
80    where
81        S: serde::Serializer,
82    {
83        serializer.serialize_u8(*self as u8)
84    }
85}
86
87impl<'de> serde::Deserialize<'de> for Face {
88    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
89    where
90        D: serde::Deserializer<'de>,
91    {
92        let value = u8::deserialize(deserializer)?;
93        match value {
94            0 => Ok(Face::Face0),
95            1 => Ok(Face::Face1),
96            2 => Ok(Face::Face2),
97            3 => Ok(Face::Face3),
98            4 => Ok(Face::Face4),
99            5 => Ok(Face::Face5),
100            _ => Err(serde::de::Error::custom("Invalid face value")),
101        }
102    }
103}
104
105/// FeatureCollection type string
106#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
107pub enum FeatureCollectionType {
108    /// WG FeatureCollection
109    #[default]
110    FeatureCollection,
111}
112impl From<&str> for FeatureCollectionType {
113    fn from(_: &str) -> Self {
114        FeatureCollectionType::FeatureCollection
115    }
116}
117
118/// FeatureCollection type string
119#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
120pub enum S2FeatureCollectionType {
121    /// WG FeatureCollection
122    #[default]
123    S2FeatureCollection,
124}
125impl From<&str> for S2FeatureCollectionType {
126    fn from(_: &str) -> Self {
127        S2FeatureCollectionType::S2FeatureCollection
128    }
129}
130
131//? FeatureCollections
132
133/// WG FeatureCollection
134#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
135pub struct FeatureCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
136    /// Type will always be "FeatureCollection"
137    #[serde(rename = "type")]
138    pub _type: FeatureCollectionType,
139    /// Collection of WG features
140    pub features: Vec<Features<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: Clone + Default, D: Clone + Default> 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<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue>
165{
166    /// Type will always be "S2FeatureCollection"
167    #[serde(rename = "type")]
168    pub _type: S2FeatureCollectionType,
169    /// Collection of S2 features
170    pub features: Vec<VectorFeature<M, P, D>>,
171    /// Track the faces that were used to generate the features
172    pub faces: Vec<Face>,
173    /// Attribution data
174    #[serde(skip_serializing_if = "Option::is_none")]
175    pub attributions: Option<Attributions>,
176    /// Bounding box
177    #[serde(skip_serializing_if = "Option::is_none")]
178    pub bbox: Option<BBox>,
179}
180impl<M, P: Clone + Default, D: Clone + Default> S2FeatureCollection<M, P, D> {
181    /// Create a new S2FeatureCollection
182    pub fn new(attributions: Option<Attributions>) -> Self {
183        Self {
184            _type: "S2FeatureCollection".into(),
185            features: Vec::new(),
186            faces: Vec::new(),
187            attributions,
188            bbox: None,
189        }
190    }
191
192    /// update the bounding box
193    pub fn update_bbox(&mut self, bbox: BBox) {
194        let mut self_bbox = self.bbox.unwrap_or_default();
195        self_bbox = self_bbox.merge(&bbox);
196        self.bbox = Some(self_bbox);
197    }
198
199    /// Add a face, ensuring it is unique
200    pub fn add_face(&mut self, face: Face) {
201        if !self.faces.contains(&face) {
202            self.faces.push(face);
203        }
204    }
205}
206
207//? Features
208
209/// Feature type string
210#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
211pub enum FeatureType {
212    /// WG Feature
213    #[default]
214    Feature,
215}
216impl From<&str> for FeatureType {
217    fn from(_: &str) -> Self {
218        FeatureType::Feature
219    }
220}
221
222/// Component to build an WG Feature
223#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
224pub struct Feature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
225    /// Type will always be "Feature"
226    #[serde(rename = "type")]
227    pub _type: FeatureType,
228    /// Unique identifier
229    #[serde(skip_serializing_if = "Option::is_none")]
230    pub id: Option<u64>,
231    /// Properties of the feature
232    pub properties: P,
233    /// Geometry of the feature
234    pub geometry: Geometry<D>,
235    /// Metadata of the feature
236    #[serde(skip_serializing_if = "Option::is_none")]
237    pub metadata: Option<M>,
238}
239impl<M, P: Clone + Default, D: Clone + Default> Feature<M, P, D> {
240    /// Create a new Feature
241    pub fn new(id: Option<u64>, properties: P, geometry: Geometry<D>, metadata: Option<M>) -> Self {
242        Self { _type: "Feature".into(), id, properties, geometry, metadata }
243    }
244}
245impl<M, P: Clone + Default, D: Clone + Default> Default for Feature<M, P, D> {
246    fn default() -> Self {
247        Self {
248            _type: "Feature".into(),
249            id: None,
250            properties: Default::default(),
251            geometry: Default::default(),
252            metadata: None,
253        }
254    }
255}
256
257/// Feature type string
258#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
259pub enum VectorFeatureType {
260    /// WG Feature
261    #[default]
262    VectorFeature,
263    /// S2 Feature
264    S2Feature,
265}
266impl From<&str> for VectorFeatureType {
267    fn from(s: &str) -> Self {
268        match s {
269            "S2Feature" => VectorFeatureType::S2Feature,
270            _ => VectorFeatureType::VectorFeature,
271        }
272    }
273}
274
275/// Component to build an WG or S2 Vector Feature
276#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
277pub struct VectorFeature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
278    /// Type will always be "VectorFeature"
279    #[serde(rename = "type")]
280    pub _type: VectorFeatureType,
281    /// Unique identifier
282    #[serde(skip_serializing_if = "Option::is_none")]
283    pub id: Option<u64>,
284    /// Face of the feature
285    pub face: Face,
286    /// Properties of the feature
287    pub properties: P,
288    /// Geometry of the feature
289    pub geometry: VectorGeometry<D>,
290    /// Metadata of the feature
291    #[serde(skip_serializing_if = "Option::is_none")]
292    pub metadata: Option<M>,
293}
294impl<M, P: Clone + Default, D: Clone + Default> Default for VectorFeature<M, P, D> {
295    fn default() -> Self {
296        Self {
297            _type: "VectorFeature".into(),
298            face: 0.into(),
299            id: None,
300            properties: Default::default(),
301            geometry: Default::default(),
302            metadata: None,
303        }
304    }
305}
306impl<M, P: Clone + Default, D: Clone + Default> VectorFeature<M, P, D> {
307    /// Create a new VectorFeature in the WG format
308    pub fn new_wm(
309        id: Option<u64>,
310        properties: P,
311        geometry: VectorGeometry<D>,
312        metadata: Option<M>,
313    ) -> Self {
314        Self { _type: "VectorFeature".into(), face: 0.into(), id, properties, geometry, metadata }
315    }
316
317    /// Create a new VectorFeature in the WG format
318    pub fn new_s2(
319        id: Option<u64>,
320        face: Face,
321        properties: P,
322        geometry: VectorGeometry<D>,
323        metadata: Option<M>,
324    ) -> Self {
325        Self { _type: "S2Feature".into(), face, id, properties, geometry, metadata }
326    }
327
328    /// Create a new VectorFeature using an input VectorFeature. Assign new geometry if provided
329    pub fn from_vector_feature(
330        feature: &VectorFeature<M, P, D>,
331        geometry: Option<VectorGeometry<D>>,
332    ) -> Self
333    where
334        M: Clone,
335    {
336        Self {
337            _type: feature._type.clone(),
338            id: feature.id,
339            face: feature.face,
340            properties: feature.properties.clone(),
341            geometry: geometry.unwrap_or(feature.geometry.clone()),
342            metadata: feature.metadata.clone(),
343        }
344    }
345
346    /// Create a VectorFeature that set's properties and geometry to m-values.
347    /// Update the metadata to user defined value
348    pub fn to_m_vector_feature<M2>(
349        &self,
350        to_meta: impl FnOnce(Option<&M>) -> Option<M2>,
351    ) -> VectorFeature<M2, Properties, MValue>
352    where
353        M: Clone,
354        P: MValueCompatible,
355        D: MValueCompatible,
356    {
357        VectorFeature {
358            _type: self._type.clone(),
359            id: self.id,
360            face: self.face,
361            properties: self.properties.clone().into(),
362            geometry: self.geometry.to_m_geometry(),
363            metadata: to_meta(self.metadata.as_ref()),
364        }
365    }
366}
367
368//? Utility types
369
370/// Attribution data is stored in an object.
371/// The key is the name of the attribution, and the value is the href link
372/// e.g. { "Open S2": "https://opens2.com/legal/data" }
373pub type Attributions = Map<String, String>;
374
375/// Either an S2 or WG FeatureCollection
376#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
377#[serde(untagged)]
378pub enum FeatureCollections<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
379    /// An WG FeatureCollection
380    FeatureCollection(FeatureCollection<M, P, D>),
381    /// An S2 FeatureCollection
382    S2FeatureCollection(S2FeatureCollection<M, P, D>),
383}
384
385/// Either an S2, Vector WG or WG Feature
386#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
387#[serde(untagged)]
388pub enum Features<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
389    /// An WG Feature
390    Feature(Feature<M, P, D>),
391    /// An WG or S2 Vector Feature
392    VectorFeature(VectorFeature<M, P, D>),
393}
394
395/// All major S2JSON types
396#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
397#[serde(untagged)]
398pub enum JSONCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
399    /// An WG FeatureCollection
400    FeatureCollection(FeatureCollection<M, P, D>),
401    /// An S2 FeatureCollection
402    S2FeatureCollection(S2FeatureCollection<M, P, D>),
403    /// An WG Feature
404    Feature(Feature<M, P, D>),
405    /// An WG Vector Feature
406    VectorFeature(VectorFeature<M, P, D>),
407}