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