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    #[serde(default)]
233    pub properties: P,
234    /// Geometry of the feature
235    pub geometry: Geometry<D>,
236    /// Metadata of the feature
237    #[serde(skip_serializing_if = "Option::is_none")]
238    pub metadata: Option<M>,
239}
240impl<M, P: Clone + Default, D: Clone + Default> Feature<M, P, D> {
241    /// Create a new Feature
242    pub fn new(id: Option<u64>, properties: P, geometry: Geometry<D>, metadata: Option<M>) -> Self {
243        Self { _type: "Feature".into(), id, properties, geometry, metadata }
244    }
245}
246impl<M, P: Clone + Default, D: Clone + Default> Default for Feature<M, P, D> {
247    fn default() -> Self {
248        Self {
249            _type: "Feature".into(),
250            id: None,
251            properties: Default::default(),
252            geometry: Default::default(),
253            metadata: None,
254        }
255    }
256}
257
258/// Feature type string
259#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Default)]
260pub enum VectorFeatureType {
261    /// WG Feature
262    #[default]
263    VectorFeature,
264    /// S2 Feature
265    S2Feature,
266}
267impl From<&str> for VectorFeatureType {
268    fn from(s: &str) -> Self {
269        match s {
270            "S2Feature" => VectorFeatureType::S2Feature,
271            _ => VectorFeatureType::VectorFeature,
272        }
273    }
274}
275
276/// Component to build an WG or S2 Vector Feature
277#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
278pub struct VectorFeature<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
279    /// Type will always be "VectorFeature"
280    #[serde(rename = "type")]
281    pub _type: VectorFeatureType,
282    /// Unique identifier
283    #[serde(skip_serializing_if = "Option::is_none")]
284    pub id: Option<u64>,
285    /// Face of the feature
286    #[serde(default)]
287    pub face: Face,
288    /// Properties of the feature
289    #[serde(default)]
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: Clone + Default, D: Clone + Default> 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: Clone + Default, D: Clone + Default> VectorFeature<M, P, D> {
310    /// Create a new VectorFeature in the WG 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 WG 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    /// Create a VectorFeature that set's properties and geometry to m-values.
350    /// Update the metadata to user defined value
351    pub fn to_m_vector_feature<M2>(
352        &self,
353        to_meta: impl FnOnce(Option<&M>) -> Option<M2>,
354    ) -> VectorFeature<M2, Properties, MValue>
355    where
356        M: Clone,
357        P: MValueCompatible,
358        D: MValueCompatible,
359    {
360        VectorFeature {
361            _type: self._type.clone(),
362            id: self.id,
363            face: self.face,
364            properties: self.properties.clone().into(),
365            geometry: self.geometry.to_m_geometry(),
366            metadata: to_meta(self.metadata.as_ref()),
367        }
368    }
369}
370
371//? Utility types
372
373/// Attribution data is stored in an object.
374/// The key is the name of the attribution, and the value is the href link
375/// e.g. { "Open S2": "https://opens2.com/legal/data" }
376pub type Attributions = Map<String, String>;
377
378/// Either an S2 or WG FeatureCollection
379#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
380#[serde(untagged)]
381pub enum FeatureCollections<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
382    /// An WG FeatureCollection
383    FeatureCollection(FeatureCollection<M, P, D>),
384    /// An S2 FeatureCollection
385    S2FeatureCollection(S2FeatureCollection<M, P, D>),
386}
387
388/// Either an S2, Vector WG or WG Feature
389#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
390#[serde(untagged)]
391pub enum Features<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
392    /// An WG Feature
393    Feature(Feature<M, P, D>),
394    /// An WG or S2 Vector Feature
395    VectorFeature(VectorFeature<M, P, D>),
396}
397
398/// All major S2JSON types
399#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
400#[serde(untagged)]
401pub enum JSONCollection<M = (), P: Clone + Default = Properties, D: Clone + Default = MValue> {
402    /// An WG FeatureCollection
403    FeatureCollection(FeatureCollection<M, P, D>),
404    /// An S2 FeatureCollection
405    S2FeatureCollection(S2FeatureCollection<M, P, D>),
406    /// An WG Feature
407    Feature(Feature<M, P, D>),
408    /// An WG Vector Feature
409    VectorFeature(VectorFeature<M, P, D>),
410}