1#![no_std]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4extern crate alloc;
7
8use alloc::{
9 borrow::ToOwned,
10 boxed::Box,
11 collections::{BTreeMap, BTreeSet},
12 format,
13 string::String,
14 vec::Vec,
15};
16pub use s2json::*;
17use serde::{Deserialize, Deserializer, Serialize, Serializer};
18
19pub type LonLatBounds = BBox<f64>;
21
22pub type TileBounds = BBox<u64>;
24
25#[derive(Copy, Clone, Debug, PartialEq)]
27pub enum DrawType {
28 Points = 1,
30 Lines = 2,
32 Polygons = 3,
34 Points3D = 4,
36 Lines3D = 5,
38 Polygons3D = 6,
40 Raster = 7,
42 Grid = 8,
44}
45impl From<DrawType> for u8 {
46 fn from(draw_type: DrawType) -> Self {
47 draw_type as u8
48 }
49}
50impl From<u8> for DrawType {
51 fn from(draw_type: u8) -> Self {
52 match draw_type {
53 2 => DrawType::Lines,
54 3 => DrawType::Polygons,
55 4 => DrawType::Points3D,
56 5 => DrawType::Lines3D,
57 6 => DrawType::Polygons3D,
58 7 => DrawType::Raster,
59 8 => DrawType::Grid,
60 _ => DrawType::Points, }
62 }
63}
64impl<D: MValueCompatible> From<&VectorGeometry<D>> for DrawType {
65 fn from(geometry: &VectorGeometry<D>) -> DrawType {
66 match geometry {
67 VectorGeometry::Point(p) => {
68 if p.is_3d {
69 DrawType::Points3D
70 } else {
71 DrawType::Points
72 }
73 }
74 VectorGeometry::MultiPoint(mp) => {
75 if mp.is_3d {
76 DrawType::Points3D
77 } else {
78 DrawType::Points
79 }
80 }
81 VectorGeometry::LineString(l) => {
82 if l.is_3d {
83 DrawType::Lines3D
84 } else {
85 DrawType::Lines
86 }
87 }
88 VectorGeometry::MultiLineString(ml) => {
89 if ml.is_3d {
90 DrawType::Lines3D
91 } else {
92 DrawType::Lines
93 }
94 }
95 VectorGeometry::Polygon(p) => {
96 if p.is_3d {
97 DrawType::Polygons3D
98 } else {
99 DrawType::Polygons
100 }
101 }
102 VectorGeometry::MultiPolygon(mp) => {
103 if mp.is_3d {
104 DrawType::Polygons3D
105 } else {
106 DrawType::Polygons
107 }
108 }
109 }
110 }
111}
112impl<M: Clone, P: MValueCompatible, D: MValueCompatible> From<&VectorFeature<M, P, D>>
113 for DrawType
114{
115 fn from(feature: &VectorFeature<M, P, D>) -> DrawType {
116 DrawType::from(&feature.geometry)
117 }
118}
119impl Serialize for DrawType {
120 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
121 where
122 S: Serializer,
123 {
124 serializer.serialize_u8(*self as u8)
126 }
127}
128
129impl<'de> Deserialize<'de> for DrawType {
130 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
131 where
132 D: Deserializer<'de>,
133 {
134 let value: u8 = Deserialize::deserialize(deserializer)?;
136 match value {
137 1 => Ok(DrawType::Points),
138 2 => Ok(DrawType::Lines),
139 3 => Ok(DrawType::Polygons),
140 4 => Ok(DrawType::Points3D),
141 5 => Ok(DrawType::Lines3D),
142 6 => Ok(DrawType::Polygons3D),
143 7 => Ok(DrawType::Raster),
144 8 => Ok(DrawType::Grid),
145 _ => Err(serde::de::Error::custom(format!("unknown DrawType variant: {}", value))),
146 }
147 }
148}
149
150#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
152pub struct LayerMetaData {
153 #[serde(skip_serializing_if = "Option::is_none")]
155 pub description: Option<String>,
156 pub minzoom: u8,
158 pub maxzoom: u8,
160 pub draw_types: Vec<DrawType>,
162 pub shape: Shape,
164 #[serde(skip_serializing_if = "Option::is_none", rename = "mShape")]
166 pub m_shape: Option<Shape>,
167}
168
169pub type LayersMetaData = BTreeMap<String, LayerMetaData>;
171
172#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
174pub struct TileStatsMetadata {
175 #[serde(default)]
177 pub total: u64,
178 #[serde(rename = "0", default)]
180 pub total_0: u64,
181 #[serde(rename = "1", default)]
183 pub total_1: u64,
184 #[serde(rename = "2", default)]
186 pub total_2: u64,
187 #[serde(rename = "3", default)]
189 pub total_3: u64,
190 #[serde(rename = "4", default)]
192 pub total_4: u64,
193 #[serde(rename = "5", default)]
195 pub total_5: u64,
196}
197impl TileStatsMetadata {
198 pub fn get(&self, face: Face) -> u64 {
200 match face {
201 Face::Face0 => self.total_0,
202 Face::Face1 => self.total_1,
203 Face::Face2 => self.total_2,
204 Face::Face3 => self.total_3,
205 Face::Face4 => self.total_4,
206 Face::Face5 => self.total_5,
207 }
208 }
209
210 pub fn increment(&mut self, face: Face) {
212 match face {
213 Face::Face0 => self.total_0 += 1,
214 Face::Face1 => self.total_1 += 1,
215 Face::Face2 => self.total_2 += 1,
216 Face::Face3 => self.total_3 += 1,
217 Face::Face4 => self.total_4 += 1,
218 Face::Face5 => self.total_5 += 1,
219 }
220 self.total += 1;
221 }
222}
223
224pub type Attributions = BTreeMap<String, String>;
227
228#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
230pub struct FaceBounds {
231 #[serde(rename = "0")]
234 pub face0: BTreeMap<u8, TileBounds>,
235 #[serde(rename = "1")]
237 pub face1: BTreeMap<u8, TileBounds>,
238 #[serde(rename = "2")]
240 pub face2: BTreeMap<u8, TileBounds>,
241 #[serde(rename = "3")]
243 pub face3: BTreeMap<u8, TileBounds>,
244 #[serde(rename = "4")]
246 pub face4: BTreeMap<u8, TileBounds>,
247 #[serde(rename = "5")]
249 pub face5: BTreeMap<u8, TileBounds>,
250}
251impl FaceBounds {
252 pub fn get(&self, face: Face) -> &BTreeMap<u8, TileBounds> {
254 match face {
255 Face::Face0 => &self.face0,
256 Face::Face1 => &self.face1,
257 Face::Face2 => &self.face2,
258 Face::Face3 => &self.face3,
259 Face::Face4 => &self.face4,
260 Face::Face5 => &self.face5,
261 }
262 }
263
264 pub fn get_mut(&mut self, face: Face) -> &mut BTreeMap<u8, TileBounds> {
266 match face {
267 Face::Face0 => &mut self.face0,
268 Face::Face1 => &mut self.face1,
269 Face::Face2 => &mut self.face2,
270 Face::Face3 => &mut self.face3,
271 Face::Face4 => &mut self.face4,
272 Face::Face5 => &mut self.face5,
273 }
274 }
275}
276
277pub type WMBounds = BTreeMap<u8, TileBounds>;
280
281#[derive(Serialize, Debug, Default, Clone, PartialEq)]
283#[serde(rename_all = "lowercase")]
284pub enum SourceType {
285 #[default]
287 Vector,
288 Json,
290 Raster,
292 #[serde(rename = "raster-dem")]
294 RasterDem,
295 Grid,
297 Markers,
299 Unknown,
301}
302impl From<&str> for SourceType {
303 fn from(source_type: &str) -> Self {
304 match source_type {
305 "vector" => SourceType::Vector,
306 "json" => SourceType::Json,
307 "raster" => SourceType::Raster,
308 "raster-dem" => SourceType::RasterDem,
309 "grid" => SourceType::Grid,
310 "markers" => SourceType::Markers,
311 _ => SourceType::Unknown,
312 }
313 }
314}
315impl<'de> Deserialize<'de> for SourceType {
316 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
317 where
318 D: Deserializer<'de>,
319 {
320 let s: String = Deserialize::deserialize(deserializer)?;
322 Ok(SourceType::from(s.as_str()))
323 }
324}
325
326#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
328#[serde(rename_all = "lowercase")]
329pub enum Encoding {
330 #[default]
332 None = 0,
333 Gzip = 1,
335 #[serde(rename = "br")]
337 Brotli = 2,
338 Zstd = 3,
340}
341impl From<u8> for Encoding {
342 fn from(encoding: u8) -> Self {
343 match encoding {
344 1 => Encoding::Gzip,
345 2 => Encoding::Brotli,
346 3 => Encoding::Zstd,
347 _ => Encoding::None,
348 }
349 }
350}
351impl From<Encoding> for u8 {
352 fn from(encoding: Encoding) -> Self {
353 match encoding {
354 Encoding::Gzip => 1,
355 Encoding::Brotli => 2,
356 Encoding::Zstd => 3,
357 Encoding::None => 0,
358 }
359 }
360}
361impl From<Encoding> for &str {
362 fn from(encoding: Encoding) -> Self {
363 match encoding {
364 Encoding::Gzip => "gzip",
365 Encoding::Brotli => "br",
366 Encoding::Zstd => "zstd",
367 Encoding::None => "none",
368 }
369 }
370}
371impl From<&str> for Encoding {
372 fn from(encoding: &str) -> Self {
373 match encoding {
374 "gzip" => Encoding::Gzip,
375 "br" => Encoding::Brotli,
376 "zstd" => Encoding::Zstd,
377 _ => Encoding::None,
378 }
379 }
380}
381
382#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
384pub struct VectorLayer {
385 pub id: String,
387 #[serde(skip_serializing_if = "Option::is_none")]
389 pub description: Option<String>,
390 #[serde(skip_serializing_if = "Option::is_none")]
392 pub minzoom: Option<u8>,
393 #[serde(skip_serializing_if = "Option::is_none")]
395 pub maxzoom: Option<u8>,
396 pub fields: BTreeMap<String, String>,
398}
399
400#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
405#[serde(rename_all = "lowercase")]
406pub enum Scheme {
407 #[default]
409 Fzxy,
410 Tfzxy,
412 Xyz,
414 Txyz,
416 Tms,
418}
419impl From<&str> for Scheme {
420 fn from(scheme: &str) -> Self {
421 match scheme {
422 "fzxy" => Scheme::Fzxy,
423 "tfzxy" => Scheme::Tfzxy,
424 "xyz" => Scheme::Xyz,
425 "txyz" => Scheme::Txyz,
426 _ => Scheme::Tms,
427 }
428 }
429}
430impl From<Scheme> for &str {
431 fn from(scheme: Scheme) -> Self {
432 match scheme {
433 Scheme::Fzxy => "fzxy",
434 Scheme::Tfzxy => "tfzxy",
435 Scheme::Xyz => "xyz",
436 Scheme::Txyz => "txyz",
437 Scheme::Tms => "tms",
438 }
439 }
440}
441
442#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
444pub struct Center {
445 pub lon: f64,
447 pub lat: f64,
449 pub zoom: u8,
451}
452
453#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
455#[serde(default)]
456pub struct Metadata {
457 pub s2tilejson: String,
459 pub version: String,
461 pub name: String,
463 pub scheme: Scheme,
465 pub description: String,
467 #[serde(rename = "type")]
469 pub r#type: SourceType,
470 pub extension: String,
472 pub encoding: Encoding,
474 pub faces: Vec<Face>,
476 pub bounds: LonLatBounds,
478 pub wmbounds: WMBounds,
480 pub s2bounds: FaceBounds,
482 pub minzoom: u8,
484 pub maxzoom: u8,
486 pub centerpoint: Center,
488 pub attributions: Attributions,
490 pub layers: LayersMetaData,
492 pub tilestats: TileStatsMetadata,
494 pub vector_layers: Vec<VectorLayer>,
496
497 pub tilejson: Option<String>,
500 #[serde(skip_serializing_if = "Option::is_none")]
502 pub tiles: Option<Vec<String>>,
503 #[serde(skip_serializing_if = "Option::is_none")]
505 pub attribution: Option<String>,
506 #[serde(skip_serializing_if = "Option::is_none")]
508 pub fillzoom: Option<u8>,
509 #[serde(skip_serializing_if = "Option::is_none")]
511 pub center: Option<[f64; 3]>,
512 #[serde(skip_serializing_if = "Option::is_none")]
514 pub data: Option<Vec<String>>,
515 #[serde(skip_serializing_if = "Option::is_none")]
517 pub grids: Option<Vec<String>>,
518 #[serde(skip_serializing_if = "Option::is_none")]
520 pub legend: Option<String>,
521 #[serde(skip_serializing_if = "Option::is_none")]
523 pub template: Option<String>,
524}
525impl Default for Metadata {
526 fn default() -> Self {
527 Self {
528 s2tilejson: "1.0.0".into(),
529 version: "1.0.0".into(),
530 name: "default".into(),
531 scheme: Scheme::default(),
532 description: "Built with s2maps-cli".into(),
533 r#type: SourceType::default(),
534 extension: "pbf".into(),
535 encoding: Encoding::default(),
536 faces: Vec::default(),
537 bounds: BBox::new(-180.0, -90.0, 180.0, 90.0),
538 wmbounds: WMBounds::default(),
539 s2bounds: FaceBounds::default(),
540 minzoom: 0,
541 maxzoom: 27,
542 centerpoint: Center::default(),
543 attributions: BTreeMap::new(),
544 layers: LayersMetaData::default(),
545 tilestats: TileStatsMetadata::default(),
546 vector_layers: Vec::new(),
547 attribution: None,
548 fillzoom: None,
549 center: None,
550 data: None,
551 grids: None,
552 legend: None,
553 template: None,
554 tilejson: None,
555 tiles: None,
556 }
557 }
558}
559
560#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
574#[serde(default)]
575pub struct MapboxTileJSONMetadata {
576 pub tilejson: String,
578 pub tiles: Vec<String>,
580 pub vector_layers: Vec<VectorLayer>,
582 #[serde(skip_serializing_if = "Option::is_none")]
584 pub attribution: Option<String>,
585 #[serde(skip_serializing_if = "Option::is_none")]
587 pub bounds: Option<LonLatBounds>,
588 #[serde(skip_serializing_if = "Option::is_none")]
590 pub center: Option<[f64; 3]>,
591 #[serde(skip_serializing_if = "Option::is_none")]
593 pub data: Option<Vec<String>>,
594 #[serde(skip_serializing_if = "Option::is_none")]
596 pub description: Option<String>,
597 #[serde(skip_serializing_if = "Option::is_none")]
599 pub fillzoom: Option<u8>,
600 #[serde(skip_serializing_if = "Option::is_none")]
602 pub grids: Option<Vec<String>>,
603 #[serde(skip_serializing_if = "Option::is_none")]
605 pub legend: Option<String>,
606 #[serde(skip_serializing_if = "Option::is_none")]
608 pub maxzoom: Option<u8>,
609 #[serde(skip_serializing_if = "Option::is_none")]
611 pub minzoom: Option<u8>,
612 #[serde(skip_serializing_if = "Option::is_none")]
614 pub name: Option<String>,
615 #[serde(skip_serializing_if = "Option::is_none")]
617 pub scheme: Option<Scheme>,
618 #[serde(skip_serializing_if = "Option::is_none")]
620 pub template: Option<String>,
621 #[serde(skip_serializing_if = "Option::is_none")]
623 pub version: Option<String>,
624 #[serde(skip_serializing_if = "Option::is_none")]
627 pub r#type: Option<SourceType>,
628 #[serde(skip_serializing_if = "Option::is_none")]
630 pub extension: Option<String>,
631 #[serde(skip_serializing_if = "Option::is_none")]
633 pub encoding: Option<Encoding>,
634}
635impl MapboxTileJSONMetadata {
636 pub fn to_metadata(&self) -> Metadata {
638 let [lon, lat, zoom] = self.center.unwrap_or([0.0, 0.0, 0.0]);
639 Metadata {
640 s2tilejson: "1.0.0".into(),
641 version: self.version.clone().unwrap_or("1.0.0".into()),
642 name: self.name.clone().unwrap_or("default".into()),
643 scheme: self.scheme.clone().unwrap_or_default(),
644 description: self.description.clone().unwrap_or("Built with s2maps-cli".into()),
645 r#type: self.r#type.clone().unwrap_or_default(),
646 extension: self.extension.clone().unwrap_or("pbf".into()),
647 faces: Vec::from([Face::Face0]),
648 bounds: self.bounds.unwrap_or_default(),
649 minzoom: self.minzoom.unwrap_or(0),
650 maxzoom: self.maxzoom.unwrap_or(27),
651 centerpoint: Center { lon, lat, zoom: zoom as u8 },
652 center: Some([lon, lat, zoom]),
653 attributions: extract_link_info(self.attribution.as_ref().unwrap_or(&"".into()))
654 .unwrap_or_default(),
655 vector_layers: self.vector_layers.clone(),
656 encoding: self.encoding.clone().unwrap_or(Encoding::None),
657 attribution: self.attribution.clone(),
658 tiles: Some(self.tiles.clone()),
659 data: self.data.clone(),
660 grids: self.grids.clone(),
661 legend: self.legend.clone(),
662 template: self.template.clone(),
663 fillzoom: self.fillzoom,
664 ..Default::default()
665 }
666 }
667}
668
669#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
671#[serde(untagged)]
672pub enum UnknownMetadata {
673 Metadata(Box<Metadata>),
675 Mapbox(Box<MapboxTileJSONMetadata>),
677}
678impl UnknownMetadata {
679 pub fn to_metadata(&self) -> Metadata {
681 match self {
682 UnknownMetadata::Metadata(m) => *m.clone(),
683 UnknownMetadata::Mapbox(m) => m.to_metadata(),
684 }
685 }
686}
687
688#[derive(Debug, Clone)]
690pub struct MetadataBuilder {
691 lon_lat_bounds: LonLatBounds,
692 faces: BTreeSet<Face>,
693 metadata: Metadata,
694}
695impl Default for MetadataBuilder {
696 fn default() -> Self {
697 MetadataBuilder {
698 lon_lat_bounds: BBox {
699 left: f64::INFINITY,
700 bottom: f64::INFINITY,
701 right: -f64::INFINITY,
702 top: -f64::INFINITY,
703 },
704 faces: BTreeSet::new(),
705 metadata: Metadata { minzoom: 30, maxzoom: 0, ..Metadata::default() },
706 }
707 }
708}
709impl MetadataBuilder {
710 pub fn commit(&mut self) -> Metadata {
712 self.update_center();
714 self.metadata.bounds = self.lon_lat_bounds;
716 for face in &self.faces {
718 self.metadata.faces.push(*face);
719 }
720 self.metadata.to_owned()
722 }
723
724 pub fn set_name(&mut self, name: String) {
726 self.metadata.name = name;
727 }
728
729 pub fn set_scheme(&mut self, scheme: Scheme) {
731 self.metadata.scheme = scheme;
732 }
733
734 pub fn set_extension(&mut self, extension: String) {
736 self.metadata.extension = extension;
737 }
738
739 pub fn set_type(&mut self, r#type: SourceType) {
741 self.metadata.r#type = r#type;
742 }
743
744 pub fn set_version(&mut self, version: String) {
746 self.metadata.version = version;
747 }
748
749 pub fn set_description(&mut self, description: String) {
751 self.metadata.description = description;
752 }
753
754 pub fn set_encoding(&mut self, encoding: Encoding) {
756 self.metadata.encoding = encoding;
757 }
758
759 pub fn add_attribution(&mut self, display_name: &str, href: &str) {
761 self.metadata.attributions.insert(display_name.into(), href.into());
762 }
763
764 pub fn add_layer(&mut self, name: &str, layer: &LayerMetaData) {
766 if self.metadata.layers.entry(name.into()).or_insert(layer.clone()).eq(&layer) {
768 self.metadata.vector_layers.push(VectorLayer {
770 id: name.into(), description: layer.description.clone(),
772 minzoom: Some(layer.minzoom),
773 maxzoom: Some(layer.maxzoom),
774 fields: BTreeMap::new(),
775 });
776 }
777 if layer.minzoom < self.metadata.minzoom {
779 self.metadata.minzoom = layer.minzoom;
780 }
781 if layer.maxzoom > self.metadata.maxzoom {
782 self.metadata.maxzoom = layer.maxzoom;
783 }
784 }
785
786 pub fn add_tile_wm(&mut self, zoom: u8, x: u32, y: u32, ll_bounds: &LonLatBounds) {
788 self.metadata.tilestats.total += 1;
789 self.faces.insert(Face::Face0);
790 self.add_bounds_wm(zoom, x, y);
791 self.update_lon_lat_bounds(ll_bounds);
792 }
793
794 pub fn add_tile_s2(&mut self, face: Face, zoom: u8, x: u32, y: u32, ll_bounds: &LonLatBounds) {
796 self.metadata.tilestats.increment(face);
797 self.faces.insert(face);
798 self.add_bounds_s2(face, zoom, x, y);
799 self.update_lon_lat_bounds(ll_bounds);
800 }
801
802 fn update_center(&mut self) {
804 let Metadata { minzoom, maxzoom, .. } = self.metadata;
805 let BBox { left, bottom, right, top } = self.lon_lat_bounds;
806 self.metadata.centerpoint.lon = (left + right) / 2.0;
807 self.metadata.centerpoint.lat = (bottom + top) / 2.0;
808 self.metadata.centerpoint.zoom = (minzoom + maxzoom) >> 1;
809 }
810
811 fn add_bounds_wm(&mut self, zoom: u8, x: u32, y: u32) {
813 let x = x as u64;
814 let y = y as u64;
815 let bbox = self.metadata.wmbounds.entry(zoom).or_insert(BBox {
816 left: u64::MAX,
817 bottom: u64::MAX,
818 right: 0,
819 top: 0,
820 });
821
822 bbox.left = bbox.left.min(x);
823 bbox.bottom = bbox.bottom.min(y);
824 bbox.right = bbox.right.max(x);
825 bbox.top = bbox.top.max(y);
826 }
827
828 fn add_bounds_s2(&mut self, face: Face, zoom: u8, x: u32, y: u32) {
830 let x = x as u64;
831 let y = y as u64;
832 let bbox = self.metadata.s2bounds.get_mut(face).entry(zoom).or_insert(BBox {
833 left: u64::MAX,
834 bottom: u64::MAX,
835 right: 0,
836 top: 0,
837 });
838
839 bbox.left = bbox.left.min(x);
840 bbox.bottom = bbox.bottom.min(y);
841 bbox.right = bbox.right.max(x);
842 bbox.top = bbox.top.max(y);
843 }
844
845 fn update_lon_lat_bounds(&mut self, ll_bounds: &LonLatBounds) {
847 self.lon_lat_bounds.left = ll_bounds.left.min(self.lon_lat_bounds.left);
848 self.lon_lat_bounds.bottom = ll_bounds.bottom.min(self.lon_lat_bounds.bottom);
849 self.lon_lat_bounds.right = ll_bounds.right.max(self.lon_lat_bounds.right);
850 self.lon_lat_bounds.top = ll_bounds.top.max(self.lon_lat_bounds.top);
851 }
852}
853
854fn extract_link_info(html_string: &str) -> Option<Attributions> {
856 let href_start = html_string.find("href='")?;
858 let href_value_start = href_start + "href='".len();
859 let href_end = html_string[href_value_start..].find("'")?;
860 let href_value = &html_string[href_value_start..href_value_start + href_end];
861
862 let text_start = html_string.find(">")?;
864 let text_value_start = text_start + 1;
865 let text_end = html_string.find("</a>")?;
866 let text_value = &html_string[text_value_start..text_end];
867
868 let mut map = BTreeMap::new();
869 map.insert(text_value.into(), href_value.into());
870
871 Some(map)
872}
873
874#[cfg(test)]
875mod tests {
876 use super::*;
877 use alloc::vec;
878 use s2json::{PrimitiveShape, ShapeType};
879
880 #[test]
881 fn it_works() {
882 let mut meta_builder = MetadataBuilder::default();
883
884 meta_builder.set_name("OSM".into());
886 meta_builder.set_description("A free editable map of the whole world.".into());
887 meta_builder.set_version("1.0.0".into());
888 meta_builder.set_scheme("fzxy".into()); meta_builder.set_type("vector".into()); meta_builder.set_encoding("none".into()); meta_builder.set_extension("pbf".into());
892 meta_builder.add_attribution("OpenStreetMap", "https://www.openstreetmap.org/copyright/");
893
894 let shape_str = r#"
896 {
897 "class": "string",
898 "offset": "f64",
899 "info": {
900 "name": "string",
901 "value": "i64"
902 }
903 }
904 "#;
905 let shape: Shape =
906 serde_json::from_str(shape_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
907 let layer = LayerMetaData {
908 minzoom: 0,
909 maxzoom: 13,
910 description: Some("water_lines".into()),
911 draw_types: Vec::from(&[DrawType::Lines]),
912 shape: shape.clone(),
913 m_shape: None,
914 };
915 meta_builder.add_layer("water_lines", &layer);
916
917 meta_builder.add_tile_wm(
920 0,
921 0,
922 0,
923 &LonLatBounds { left: -60.0, bottom: -20.0, right: 5.0, top: 60.0 },
924 );
925 meta_builder.add_tile_s2(
927 Face::Face1,
928 5,
929 22,
930 37,
931 &LonLatBounds { left: -120.0, bottom: -7.0, right: 44.0, top: 72.0 },
932 );
933
934 let resulting_metadata: Metadata = meta_builder.commit();
936
937 assert_eq!(
938 resulting_metadata,
939 Metadata {
940 name: "OSM".into(),
941 description: "A free editable map of the whole world.".into(),
942 version: "1.0.0".into(),
943 scheme: "fzxy".into(),
944 r#type: "vector".into(),
945 encoding: "none".into(),
946 extension: "pbf".into(),
947 attributions: BTreeMap::from([(
948 "OpenStreetMap".into(),
949 "https://www.openstreetmap.org/copyright/".into()
950 ),]),
951 wmbounds: BTreeMap::from([(
952 0,
953 TileBounds { left: 0, bottom: 0, right: 0, top: 0 }
954 ),]),
955 faces: Vec::from(&[Face::Face0, Face::Face1]),
956 bounds: BBox { left: -120.0, bottom: -20.0, right: 44.0, top: 72.0 },
957 s2bounds: FaceBounds {
958 face0: BTreeMap::new(),
959 face1: BTreeMap::from([(
960 5,
961 TileBounds { left: 22, bottom: 37, right: 22, top: 37 }
962 ),]),
963 face2: BTreeMap::new(),
964 face3: BTreeMap::new(),
965 face4: BTreeMap::new(),
966 face5: BTreeMap::new(),
967 },
968 minzoom: 0,
969 maxzoom: 13,
970 centerpoint: Center { lon: -38.0, lat: 26.0, zoom: 6 },
972 tilestats: TileStatsMetadata {
973 total: 2,
974 total_0: 0,
975 total_1: 1,
976 total_2: 0,
977 total_3: 0,
978 total_4: 0,
979 total_5: 0,
980 },
981 layers: BTreeMap::from([(
982 "water_lines".into(),
983 LayerMetaData {
984 description: Some("water_lines".into()),
985 minzoom: 0,
986 maxzoom: 13,
987 draw_types: Vec::from(&[DrawType::Lines]),
988 shape: Shape::from([
989 ("class".into(), ShapeType::Primitive(PrimitiveShape::String)),
990 ("offset".into(), ShapeType::Primitive(PrimitiveShape::F64)),
991 (
992 "info".into(),
993 ShapeType::Nested(Shape::from([
994 ("name".into(), ShapeType::Primitive(PrimitiveShape::String)),
995 ("value".into(), ShapeType::Primitive(PrimitiveShape::I64)),
996 ]))
997 ),
998 ]),
999 m_shape: None,
1000 }
1001 )]),
1002 s2tilejson: "1.0.0".into(),
1003 vector_layers: Vec::from([VectorLayer {
1004 id: "water_lines".into(),
1005 description: Some("water_lines".into()),
1006 minzoom: Some(0),
1007 maxzoom: Some(13),
1008 fields: BTreeMap::new()
1009 }]),
1010 ..Default::default()
1011 }
1012 );
1013
1014 let meta_str = serde_json::to_string(&resulting_metadata).unwrap();
1015
1016 assert_eq!(
1017 meta_str,
1018 "{\"s2tilejson\":\"1.0.0\",\"version\":\"1.0.0\",\"name\":\"OSM\",\"scheme\":\"fzxy\",\"description\":\"A free editable map of the whole world.\",\"type\":\"vector\",\"extension\":\"pbf\",\"encoding\":\"none\",\"faces\":[0,1],\"bounds\":[-120.0,-20.0,44.0,72.0],\"wmbounds\":{\"0\":[0,0,0,0]},\"s2bounds\":{\"0\":{},\"1\":{\"5\":[22,37,22,37]},\"2\":{},\"3\":{},\"4\":{},\"5\":{}},\"minzoom\":0,\"maxzoom\":13,\"centerpoint\":{\"lon\":-38.0,\"lat\":26.0,\"zoom\":6},\"attributions\":{\"OpenStreetMap\":\"https://www.openstreetmap.org/copyright/\"},\"layers\":{\"water_lines\":{\"description\":\"water_lines\",\"minzoom\":0,\"maxzoom\":13,\"draw_types\":[2],\"shape\":{\"class\":\"string\",\"info\":{\"name\":\"string\",\"value\":\"i64\"},\"offset\":\"f64\"}}},\"tilestats\":{\"total\":2,\"0\":0,\"1\":1,\"2\":0,\"3\":0,\"4\":0,\"5\":0},\"vector_layers\":[{\"id\":\"water_lines\",\"description\":\"water_lines\",\"minzoom\":0,\"maxzoom\":13,\"fields\":{}}],\"tilejson\":null}"
1019 );
1020
1021 let meta_reparsed: Metadata =
1022 serde_json::from_str(&meta_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
1023 assert_eq!(meta_reparsed, resulting_metadata);
1024 }
1025
1026 #[test]
1027 fn test_face() {
1028 assert_eq!(Face::Face0, Face::from(0));
1029 assert_eq!(Face::Face1, Face::from(1));
1030 assert_eq!(Face::Face2, Face::from(2));
1031 assert_eq!(Face::Face3, Face::from(3));
1032 assert_eq!(Face::Face4, Face::from(4));
1033 assert_eq!(Face::Face5, Face::from(5));
1034
1035 assert_eq!(0, u8::from(Face::Face0));
1036 assert_eq!(1, u8::from(Face::Face1));
1037 assert_eq!(2, u8::from(Face::Face2));
1038 assert_eq!(3, u8::from(Face::Face3));
1039 assert_eq!(4, u8::from(Face::Face4));
1040 assert_eq!(5, u8::from(Face::Face5));
1041 }
1042
1043 #[test]
1044 fn test_bbox() {
1045 let bbox: BBox = BBox { left: 0.0, bottom: 0.0, right: 0.0, top: 0.0 };
1046 let json = serde_json::to_string(&bbox).unwrap();
1048 assert_eq!(json, r#"[0.0,0.0,0.0,0.0]"#);
1049 let bbox2: BBox = serde_json::from_str(&json).unwrap();
1050 assert_eq!(bbox, bbox2);
1051 }
1052
1053 #[test]
1055 fn test_tilestats() {
1056 let mut tilestats = TileStatsMetadata {
1057 total: 2,
1058 total_0: 0,
1059 total_1: 1,
1060 total_2: 0,
1061 total_3: 0,
1062 total_4: 0,
1063 total_5: 0,
1064 };
1065 let json = serde_json::to_string(&tilestats).unwrap();
1067 assert_eq!(json, r#"{"total":2,"0":0,"1":1,"2":0,"3":0,"4":0,"5":0}"#);
1068 let tilestats2: TileStatsMetadata = serde_json::from_str(&json).unwrap();
1069 assert_eq!(tilestats, tilestats2);
1070
1071 assert_eq!(tilestats.get(0.into()), 0);
1073 tilestats.increment(0.into());
1075 assert_eq!(tilestats.get(0.into()), 1);
1076
1077 assert_eq!(tilestats.get(1.into()), 1);
1079 tilestats.increment(1.into());
1081 assert_eq!(tilestats.get(1.into()), 2);
1082
1083 assert_eq!(tilestats.get(2.into()), 0);
1085 tilestats.increment(2.into());
1087 assert_eq!(tilestats.get(2.into()), 1);
1088
1089 assert_eq!(tilestats.get(3.into()), 0);
1091 tilestats.increment(3.into());
1093 assert_eq!(tilestats.get(3.into()), 1);
1094
1095 assert_eq!(tilestats.get(4.into()), 0);
1097 tilestats.increment(4.into());
1099 assert_eq!(tilestats.get(4.into()), 1);
1100
1101 assert_eq!(tilestats.get(5.into()), 0);
1103 tilestats.increment(5.into());
1105 assert_eq!(tilestats.get(5.into()), 1);
1106 }
1107
1108 #[test]
1110 fn test_facebounds() {
1111 let mut facebounds = FaceBounds::default();
1112 let face0 = facebounds.get_mut(0.into());
1114 face0.insert(0, TileBounds { left: 0, bottom: 0, right: 0, top: 0 });
1115 let face1 = facebounds.get_mut(1.into());
1117 face1.insert(0, TileBounds { left: 0, bottom: 0, right: 1, top: 1 });
1118 let face2 = facebounds.get_mut(2.into());
1120 face2.insert(0, TileBounds { left: 0, bottom: 0, right: 2, top: 2 });
1121 let face3 = facebounds.get_mut(3.into());
1123 face3.insert(0, TileBounds { left: 0, bottom: 0, right: 3, top: 3 });
1124 let face4 = facebounds.get_mut(4.into());
1126 face4.insert(0, TileBounds { left: 0, bottom: 0, right: 4, top: 4 });
1127 let face5 = facebounds.get_mut(5.into());
1129 face5.insert(0, TileBounds { left: 0, bottom: 0, right: 5, top: 5 });
1130
1131 assert_eq!(
1134 facebounds.get(0.into()).get(&0).unwrap(),
1135 &TileBounds { left: 0, bottom: 0, right: 0, top: 0 }
1136 );
1137 assert_eq!(
1139 facebounds.get(1.into()).get(&0).unwrap(),
1140 &TileBounds { left: 0, bottom: 0, right: 1, top: 1 }
1141 );
1142 assert_eq!(
1144 facebounds.get(2.into()).get(&0).unwrap(),
1145 &TileBounds { left: 0, bottom: 0, right: 2, top: 2 }
1146 );
1147 assert_eq!(
1149 facebounds.get(3.into()).get(&0).unwrap(),
1150 &TileBounds { left: 0, bottom: 0, right: 3, top: 3 }
1151 );
1152 assert_eq!(
1154 facebounds.get(4.into()).get(&0).unwrap(),
1155 &TileBounds { left: 0, bottom: 0, right: 4, top: 4 }
1156 );
1157 assert_eq!(
1159 facebounds.get(5.into()).get(&0).unwrap(),
1160 &TileBounds { left: 0, bottom: 0, right: 5, top: 5 }
1161 );
1162
1163 let json = serde_json::to_string(&facebounds).unwrap();
1165 assert_eq!(
1166 json,
1167 "{\"0\":{\"0\":[0,0,0,0]},\"1\":{\"0\":[0,0,1,1]},\"2\":{\"0\":[0,0,2,2]},\"3\":{\"0\"\
1168 :[0,0,3,3]},\"4\":{\"0\":[0,0,4,4]},\"5\":{\"0\":[0,0,5,5]}}"
1169 );
1170 let facebounds2 = serde_json::from_str(&json).unwrap();
1171 assert_eq!(facebounds, facebounds2);
1172 }
1173
1174 #[test]
1176 fn test_drawtype() {
1177 assert_eq!(DrawType::from(1), DrawType::Points);
1178 assert_eq!(DrawType::from(2), DrawType::Lines);
1179 assert_eq!(DrawType::from(3), DrawType::Polygons);
1180 assert_eq!(DrawType::from(4), DrawType::Points3D);
1181 assert_eq!(DrawType::from(5), DrawType::Lines3D);
1182 assert_eq!(DrawType::from(6), DrawType::Polygons3D);
1183 assert_eq!(DrawType::from(7), DrawType::Raster);
1184 assert_eq!(DrawType::from(8), DrawType::Grid);
1185
1186 assert_eq!(1, u8::from(DrawType::Points));
1187 assert_eq!(2, u8::from(DrawType::Lines));
1188 assert_eq!(3, u8::from(DrawType::Polygons));
1189 assert_eq!(4, u8::from(DrawType::Points3D));
1190 assert_eq!(5, u8::from(DrawType::Lines3D));
1191 assert_eq!(6, u8::from(DrawType::Polygons3D));
1192 assert_eq!(7, u8::from(DrawType::Raster));
1193 assert_eq!(8, u8::from(DrawType::Grid));
1194
1195 let json = serde_json::to_string(&DrawType::Points).unwrap();
1197 assert_eq!(json, "1");
1198 let drawtype: DrawType = serde_json::from_str(&json).unwrap();
1199 assert_eq!(drawtype, DrawType::Points);
1200
1201 let drawtype: DrawType = serde_json::from_str("2").unwrap();
1202 assert_eq!(drawtype, DrawType::Lines);
1203
1204 let drawtype: DrawType = serde_json::from_str("3").unwrap();
1205 assert_eq!(drawtype, DrawType::Polygons);
1206
1207 let drawtype: DrawType = serde_json::from_str("4").unwrap();
1208 assert_eq!(drawtype, DrawType::Points3D);
1209
1210 let drawtype: DrawType = serde_json::from_str("5").unwrap();
1211 assert_eq!(drawtype, DrawType::Lines3D);
1212
1213 let drawtype: DrawType = serde_json::from_str("6").unwrap();
1214 assert_eq!(drawtype, DrawType::Polygons3D);
1215
1216 let drawtype: DrawType = serde_json::from_str("7").unwrap();
1217 assert_eq!(drawtype, DrawType::Raster);
1218
1219 let drawtype: DrawType = serde_json::from_str("8").unwrap();
1220 assert_eq!(drawtype, DrawType::Grid);
1221
1222 assert!(serde_json::from_str::<DrawType>("9").is_err());
1223 }
1224
1225 #[test]
1227 fn test_sourcetype() {
1228 assert_eq!(SourceType::from("vector"), SourceType::Vector);
1230 assert_eq!(SourceType::from("json"), SourceType::Json);
1231 assert_eq!(SourceType::from("raster"), SourceType::Raster);
1232 assert_eq!(SourceType::from("raster-dem"), SourceType::RasterDem);
1233 assert_eq!(SourceType::from("grid"), SourceType::Grid);
1234 assert_eq!(SourceType::from("markers"), SourceType::Markers);
1235 assert_eq!(SourceType::from("overlay"), SourceType::Unknown);
1236
1237 let json = serde_json::to_string(&SourceType::Vector).unwrap();
1239 assert_eq!(json, "\"vector\"");
1240 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1241 assert_eq!(sourcetype, SourceType::Vector);
1242
1243 let json = serde_json::to_string(&SourceType::Json).unwrap();
1245 assert_eq!(json, "\"json\"");
1246 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1247 assert_eq!(sourcetype, SourceType::Json);
1248
1249 let json = serde_json::to_string(&SourceType::Raster).unwrap();
1251 assert_eq!(json, "\"raster\"");
1252 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1253 assert_eq!(sourcetype, SourceType::Raster);
1254
1255 let json = serde_json::to_string(&SourceType::RasterDem).unwrap();
1257 assert_eq!(json, "\"raster-dem\"");
1258 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1259 assert_eq!(sourcetype, SourceType::RasterDem);
1260
1261 let json = serde_json::to_string(&SourceType::Grid).unwrap();
1263 assert_eq!(json, "\"grid\"");
1264 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1265 assert_eq!(sourcetype, SourceType::Grid);
1266
1267 let json = serde_json::to_string(&SourceType::Markers).unwrap();
1269 assert_eq!(json, "\"markers\"");
1270 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1271 assert_eq!(sourcetype, SourceType::Markers);
1272
1273 let json = serde_json::to_string(&SourceType::Unknown).unwrap();
1275 assert_eq!(json, "\"unknown\"");
1276 let sourcetype: SourceType = serde_json::from_str(r#""overlay""#).unwrap();
1277 assert_eq!(sourcetype, SourceType::Unknown);
1278 }
1279
1280 #[test]
1282 fn test_encoding() {
1283 assert_eq!(Encoding::from("none"), Encoding::None);
1285 assert_eq!(Encoding::from("gzip"), Encoding::Gzip);
1286 assert_eq!(Encoding::from("br"), Encoding::Brotli);
1287 assert_eq!(Encoding::from("zstd"), Encoding::Zstd);
1288
1289 assert_eq!(core::convert::Into::<&str>::into(Encoding::None), "none");
1291 assert_eq!(core::convert::Into::<&str>::into(Encoding::Gzip), "gzip");
1292 assert_eq!(core::convert::Into::<&str>::into(Encoding::Brotli), "br");
1293 assert_eq!(core::convert::Into::<&str>::into(Encoding::Zstd), "zstd");
1294
1295 assert_eq!(Encoding::from(0), Encoding::None);
1297 assert_eq!(Encoding::from(1), Encoding::Gzip);
1298 assert_eq!(Encoding::from(2), Encoding::Brotli);
1299 assert_eq!(Encoding::from(3), Encoding::Zstd);
1300
1301 assert_eq!(u8::from(Encoding::None), 0);
1303 assert_eq!(u8::from(Encoding::Gzip), 1);
1304 assert_eq!(u8::from(Encoding::Brotli), 2);
1305 assert_eq!(u8::from(Encoding::Zstd), 3);
1306
1307 let json = serde_json::to_string(&Encoding::Gzip).unwrap();
1309 assert_eq!(json, "\"gzip\"");
1310 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1311 assert_eq!(encoding, Encoding::Gzip);
1312
1313 let json = serde_json::to_string(&Encoding::Brotli).unwrap();
1315 assert_eq!(json, "\"br\"");
1316 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1317 assert_eq!(encoding, Encoding::Brotli);
1318
1319 let json = serde_json::to_string(&Encoding::None).unwrap();
1321 assert_eq!(json, "\"none\"");
1322 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1323 assert_eq!(encoding, Encoding::None);
1324
1325 let json = serde_json::to_string(&Encoding::Zstd).unwrap();
1327 assert_eq!(json, "\"zstd\"");
1328 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1329 assert_eq!(encoding, Encoding::Zstd);
1330 }
1331
1332 #[test]
1334 fn test_scheme() {
1335 assert_eq!(Scheme::from("fzxy"), Scheme::Fzxy);
1337 assert_eq!(Scheme::from("tfzxy"), Scheme::Tfzxy);
1338 assert_eq!(Scheme::from("xyz"), Scheme::Xyz);
1339 assert_eq!(Scheme::from("txyz"), Scheme::Txyz);
1340 assert_eq!(Scheme::from("tms"), Scheme::Tms);
1341
1342 assert_eq!(core::convert::Into::<&str>::into(Scheme::Fzxy), "fzxy");
1344 assert_eq!(core::convert::Into::<&str>::into(Scheme::Tfzxy), "tfzxy");
1345 assert_eq!(core::convert::Into::<&str>::into(Scheme::Xyz), "xyz");
1346 assert_eq!(core::convert::Into::<&str>::into(Scheme::Txyz), "txyz");
1347 assert_eq!(core::convert::Into::<&str>::into(Scheme::Tms), "tms");
1348 }
1349
1350 #[test]
1351 fn test_tippecanoe_metadata() {
1352 let meta_str = r#"{
1353 "name": "test_fixture_1.pmtiles",
1354 "description": "test_fixture_1.pmtiles",
1355 "version": "2",
1356 "type": "overlay",
1357 "generator": "tippecanoe v2.5.0",
1358 "generator_options": "./tippecanoe -zg -o test_fixture_1.pmtiles --force",
1359 "vector_layers": [
1360 {
1361 "id": "test_fixture_1pmtiles",
1362 "description": "",
1363 "minzoom": 0,
1364 "maxzoom": 0,
1365 "fields": {}
1366 }
1367 ],
1368 "tilestats": {
1369 "layerCount": 1,
1370 "layers": [
1371 {
1372 "layer": "test_fixture_1pmtiles",
1373 "count": 1,
1374 "geometry": "Polygon",
1375 "attributeCount": 0,
1376 "attributes": []
1377 }
1378 ]
1379 }
1380 }"#;
1381
1382 let _meta: Metadata =
1383 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
1384 }
1385
1386 #[test]
1387 fn test_mapbox_metadata() {
1388 let meta_str = r#"{
1389 "tilejson": "3.0.0",
1390 "name": "OpenStreetMap",
1391 "description": "A free editable map of the whole world.",
1392 "version": "1.0.0",
1393 "attribution": "<a href='https://openstreetmap.org'>OSM contributors</a>",
1394 "scheme": "xyz",
1395 "tiles": [
1396 "https://a.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt",
1397 "https://b.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt",
1398 "https://c.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt"
1399 ],
1400 "minzoom": 0,
1401 "maxzoom": 18,
1402 "bounds": [-180, -85, 180, 85],
1403 "fillzoom": 6,
1404 "something_custom": "this is my unique field",
1405 "vector_layers": [
1406 {
1407 "id": "telephone",
1408 "fields": {
1409 "phone_number": "the phone number",
1410 "payment": "how to pay"
1411 }
1412 },
1413 {
1414 "id": "bicycle_parking",
1415 "fields": {
1416 "type": "the type of bike parking",
1417 "year_installed": "the year the bike parking was installed"
1418 }
1419 },
1420 {
1421 "id": "showers",
1422 "fields": {
1423 "water_temperature": "the maximum water temperature",
1424 "wear_sandles": "whether you should wear sandles or not",
1425 "wheelchair": "is the shower wheelchair friendly?"
1426 }
1427 }
1428 ]
1429 }"#;
1430
1431 let meta_mapbox: MapboxTileJSONMetadata =
1432 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
1433 let meta_new = meta_mapbox.to_metadata();
1434 assert_eq!(
1435 meta_new,
1436 Metadata {
1437 name: "OpenStreetMap".into(),
1438 description: "A free editable map of the whole world.".into(),
1439 version: "1.0.0".into(),
1440 scheme: Scheme::Xyz,
1441 r#type: "vector".into(),
1442 encoding: Encoding::None, extension: "pbf".into(),
1444 attributions: BTreeMap::from([(
1445 "OSM contributors".into(),
1446 "https://openstreetmap.org".into()
1447 )]),
1448 bounds: BBox::new(-180., -85., 180., 85.),
1449 vector_layers: meta_mapbox.vector_layers.clone(),
1450 maxzoom: 18,
1451 minzoom: 0,
1452 centerpoint: Center { lat: 0.0, lon: 0.0, zoom: 0 },
1453 wmbounds: WMBounds::default(),
1454 faces: vec![Face::Face0],
1455 s2bounds: FaceBounds::default(),
1456 tilestats: TileStatsMetadata::default(),
1457 layers: LayersMetaData::default(),
1458 s2tilejson: "1.0.0".into(),
1459 attribution: Some(
1460 "<a href='https://openstreetmap.org'>OSM contributors</a>".into()
1461 ),
1462 tiles: Some(meta_mapbox.tiles.clone()),
1463 fillzoom: meta_mapbox.fillzoom,
1464 center: Some([0.0, 0.0, 0.0]),
1465 ..Default::default()
1466 },
1467 );
1468
1469 let meta_mapbox_from_unknown: UnknownMetadata =
1470 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
1471 let meta_new = meta_mapbox_from_unknown.to_metadata();
1472 assert_eq!(
1473 meta_new,
1474 Metadata {
1475 name: "OpenStreetMap".into(),
1476 description: "A free editable map of the whole world.".into(),
1477 version: "1.0.0".into(),
1478 scheme: Scheme::Xyz,
1479 r#type: "vector".into(),
1480 encoding: Encoding::None, extension: "pbf".into(),
1482 attributions: BTreeMap::default(),
1483 bounds: BBox::new(-180., -85., 180., 85.),
1484 vector_layers: meta_mapbox.vector_layers.clone(),
1485 maxzoom: 18,
1486 minzoom: 0,
1487 centerpoint: Center { lat: 0.0, lon: 0.0, zoom: 0 },
1488 wmbounds: WMBounds::default(),
1489 faces: vec![],
1490 s2bounds: FaceBounds::default(),
1491 tilestats: TileStatsMetadata::default(),
1492 layers: LayersMetaData::default(),
1493 s2tilejson: "1.0.0".into(),
1494 attribution: Some(
1495 "<a href='https://openstreetmap.org'>OSM contributors</a>".into()
1496 ),
1497 tiles: Some(meta_mapbox.tiles.clone()),
1498 fillzoom: meta_mapbox.fillzoom,
1499 center: None,
1500 tilejson: Some("3.0.0".into()),
1501 ..Default::default()
1502 },
1503 );
1504 }
1505
1506 #[test]
1507 fn test_malformed_metadata() {
1508 let meta_str = r#"{
1509 "s2tilejson": "1.0.0",
1510 "bounds": [
1511 -180,
1512 -85,
1513 180,
1514 85
1515 ],
1516 "name": "Mapbox Satellite",
1517 "scheme": "xyz",
1518 "format": "zxy",
1519 "type": "raster",
1520 "extension": "webp",
1521 "encoding": "gzip",
1522 "minzoom": 0,
1523 "maxzoom": 3
1524 }
1525 "#;
1526
1527 let malformed_success: UnknownMetadata =
1528 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {}", e));
1529
1530 let meta: Metadata = malformed_success.to_metadata();
1531 assert_eq!(
1532 meta,
1533 Metadata {
1534 s2tilejson: "1.0.0".into(),
1535 version: "1.0.0".into(),
1536 name: "Mapbox Satellite".into(),
1537 scheme: Scheme::Xyz,
1538 description: "Built with s2maps-cli".into(),
1539 r#type: SourceType::Raster,
1540 extension: "webp".into(),
1541 encoding: Encoding::Gzip,
1542 faces: vec![],
1543 bounds: BBox::new(-180., -85., 180., 85.),
1544 wmbounds: BTreeMap::default(),
1545 s2bounds: FaceBounds {
1546 face0: BTreeMap::default(),
1547 face1: BTreeMap::default(),
1548 face2: BTreeMap::default(),
1549 face3: BTreeMap::default(),
1550 face4: BTreeMap::default(),
1551 face5: BTreeMap::default()
1552 },
1553 minzoom: 0,
1554 maxzoom: 3,
1555 centerpoint: Center { lon: 0.0, lat: 0.0, zoom: 0 },
1556 attributions: BTreeMap::default(),
1557 layers: BTreeMap::default(),
1558 tilestats: TileStatsMetadata {
1559 total: 0,
1560 total_0: 0,
1561 total_1: 0,
1562 total_2: 0,
1563 total_3: 0,
1564 total_4: 0,
1565 total_5: 0
1566 },
1567 vector_layers: vec![],
1568 ..Default::default()
1569 }
1570 );
1571 }
1572
1573 #[test]
1574 fn test_faces() {
1575 let meta = Metadata {
1576 faces: vec![Face::Face0, Face::Face1, Face::Face4, Face::Face5],
1577 ..Default::default()
1578 };
1579
1580 let to_string: String = serde_json::to_string(&meta).unwrap();
1581 let from_string: Metadata = serde_json::from_str(&to_string).unwrap();
1582 assert_eq!(meta, from_string);
1583
1584 let from_string_unknown: UnknownMetadata = serde_json::from_str(&to_string).unwrap();
1585 let from_string: Metadata = from_string_unknown.to_metadata();
1586 assert_eq!(meta, from_string);
1587 }
1588
1589 #[test]
1590 fn test_vector_feature_to_draw_type() {
1591 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1593 geometry: VectorGeometry::new_point(VectorPoint::from_xy(0., 0.), None),
1594 ..Default::default()
1595 };
1596 assert_eq!(DrawType::Points, (&feature).into());
1597 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1598 geometry: VectorGeometry::new_multipoint(vec![VectorPoint::from_xy(0., 0.)], None),
1599 ..Default::default()
1600 };
1601 assert_eq!(DrawType::Points, (&feature).into());
1602 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1604 geometry: VectorGeometry::new_point(VectorPoint::from_xyz(0., 0., 1.0), None),
1605 ..Default::default()
1606 };
1607 assert_eq!(DrawType::Points3D, (&feature).into());
1608 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1609 geometry: VectorGeometry::new_multipoint(
1610 vec![VectorPoint::from_xyz(0., 0., 1.0)],
1611 None,
1612 ),
1613 ..Default::default()
1614 };
1615 assert_eq!(DrawType::Points3D, (&feature).into());
1616 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1618 geometry: VectorGeometry::new_linestring(vec![VectorPoint::from_xy(0., 0.)], None),
1619 ..Default::default()
1620 };
1621 assert_eq!(DrawType::Lines, (&feature).into());
1622 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1623 geometry: VectorGeometry::new_multilinestring(
1624 vec![vec![VectorPoint::from_xy(0., 0.)]],
1625 None,
1626 ),
1627 ..Default::default()
1628 };
1629 assert_eq!(DrawType::Lines, (&feature).into());
1630 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1632 geometry: VectorGeometry::new_linestring(
1633 vec![VectorPoint::from_xyz(0., 0., 1.0)],
1634 None,
1635 ),
1636 ..Default::default()
1637 };
1638 assert_eq!(DrawType::Lines3D, (&feature).into());
1639 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1640 geometry: VectorGeometry::new_multilinestring(
1641 vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]],
1642 None,
1643 ),
1644 ..Default::default()
1645 };
1646 assert_eq!(DrawType::Lines3D, (&feature).into());
1647 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1649 geometry: VectorGeometry::new_polygon(vec![vec![VectorPoint::from_xy(0., 0.)]], None),
1650 ..Default::default()
1651 };
1652 assert_eq!(DrawType::Polygons, (&feature).into());
1653 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1654 geometry: VectorGeometry::new_multipolygon(
1655 vec![vec![vec![VectorPoint::from_xy(0., 0.)]]],
1656 None,
1657 ),
1658 ..Default::default()
1659 };
1660 assert_eq!(DrawType::Polygons, (&feature).into());
1661 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1663 geometry: VectorGeometry::new_polygon(
1664 vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]],
1665 None,
1666 ),
1667 ..Default::default()
1668 };
1669 assert_eq!(DrawType::Polygons3D, (&feature).into());
1670 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1671 geometry: VectorGeometry::new_multipolygon(
1672 vec![vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]]],
1673 None,
1674 ),
1675 ..Default::default()
1676 };
1677 assert_eq!(DrawType::Polygons3D, (&feature).into());
1678 }
1679}