1#![no_std]
2#![forbid(unsafe_code)]
3#![deny(missing_docs)]
4#![cfg_attr(docsrs, feature(doc_cfg))]
5
6extern crate alloc;
79
80use alloc::{
81 borrow::ToOwned,
82 boxed::Box,
83 collections::{BTreeMap, BTreeSet},
84 format,
85 string::String,
86 vec::Vec,
87};
88pub use s2json::*;
89use serde::{Deserialize, Deserializer, Serialize, Serializer};
90
91pub type LonLatBounds = BBox<f64>;
93
94pub type TileBounds = BBox<u64>;
96
97#[derive(Copy, Clone, Debug, PartialEq)]
99pub enum DrawType {
100 Points = 1,
102 Lines = 2,
104 Polygons = 3,
106 Points3D = 4,
108 Lines3D = 5,
110 Polygons3D = 6,
112 Raster = 7,
114 Grid = 8,
116}
117impl From<DrawType> for u8 {
118 fn from(draw_type: DrawType) -> Self {
119 draw_type as u8
120 }
121}
122impl From<u8> for DrawType {
123 fn from(draw_type: u8) -> Self {
124 match draw_type {
125 2 => DrawType::Lines,
126 3 => DrawType::Polygons,
127 4 => DrawType::Points3D,
128 5 => DrawType::Lines3D,
129 6 => DrawType::Polygons3D,
130 7 => DrawType::Raster,
131 8 => DrawType::Grid,
132 _ => DrawType::Points, }
134 }
135}
136impl<D: MValueCompatible> From<&VectorGeometry<D>> for DrawType {
137 fn from(geometry: &VectorGeometry<D>) -> DrawType {
138 match geometry {
139 VectorGeometry::Point(p) => {
140 if p.is_3d {
141 DrawType::Points3D
142 } else {
143 DrawType::Points
144 }
145 }
146 VectorGeometry::MultiPoint(mp) => {
147 if mp.is_3d {
148 DrawType::Points3D
149 } else {
150 DrawType::Points
151 }
152 }
153 VectorGeometry::LineString(l) => {
154 if l.is_3d {
155 DrawType::Lines3D
156 } else {
157 DrawType::Lines
158 }
159 }
160 VectorGeometry::MultiLineString(ml) => {
161 if ml.is_3d {
162 DrawType::Lines3D
163 } else {
164 DrawType::Lines
165 }
166 }
167 VectorGeometry::Polygon(p) => {
168 if p.is_3d {
169 DrawType::Polygons3D
170 } else {
171 DrawType::Polygons
172 }
173 }
174 VectorGeometry::MultiPolygon(mp) => {
175 if mp.is_3d {
176 DrawType::Polygons3D
177 } else {
178 DrawType::Polygons
179 }
180 }
181 }
182 }
183}
184impl<M: Clone, P: MValueCompatible, D: MValueCompatible> From<&VectorFeature<M, P, D>>
185 for DrawType
186{
187 fn from(feature: &VectorFeature<M, P, D>) -> DrawType {
188 DrawType::from(&feature.geometry)
189 }
190}
191impl Serialize for DrawType {
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where
194 S: Serializer,
195 {
196 serializer.serialize_u8(*self as u8)
198 }
199}
200
201impl<'de> Deserialize<'de> for DrawType {
202 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
203 where
204 D: Deserializer<'de>,
205 {
206 let value: u8 = Deserialize::deserialize(deserializer)?;
208 match value {
209 1 => Ok(DrawType::Points),
210 2 => Ok(DrawType::Lines),
211 3 => Ok(DrawType::Polygons),
212 4 => Ok(DrawType::Points3D),
213 5 => Ok(DrawType::Lines3D),
214 6 => Ok(DrawType::Polygons3D),
215 7 => Ok(DrawType::Raster),
216 8 => Ok(DrawType::Grid),
217 _ => Err(serde::de::Error::custom(format!("unknown DrawType variant: {value}"))),
218 }
219 }
220}
221
222#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
224pub struct LayerMetaData {
225 #[serde(skip_serializing_if = "Option::is_none")]
227 pub description: Option<String>,
228 pub minzoom: u8,
230 pub maxzoom: u8,
232 pub draw_types: Vec<DrawType>,
234 pub shape: Shape,
236 #[serde(skip_serializing_if = "Option::is_none", rename = "mShape")]
238 pub m_shape: Option<Shape>,
239}
240
241pub type LayersMetaData = BTreeMap<String, LayerMetaData>;
243
244#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
246pub struct TileStatsMetadata {
247 #[serde(default)]
249 pub total: u64,
250 #[serde(rename = "0", default)]
252 pub total_0: u64,
253 #[serde(rename = "1", default)]
255 pub total_1: u64,
256 #[serde(rename = "2", default)]
258 pub total_2: u64,
259 #[serde(rename = "3", default)]
261 pub total_3: u64,
262 #[serde(rename = "4", default)]
264 pub total_4: u64,
265 #[serde(rename = "5", default)]
267 pub total_5: u64,
268}
269impl TileStatsMetadata {
270 pub fn get(&self, face: Face) -> u64 {
272 match face {
273 Face::Face0 => self.total_0,
274 Face::Face1 => self.total_1,
275 Face::Face2 => self.total_2,
276 Face::Face3 => self.total_3,
277 Face::Face4 => self.total_4,
278 Face::Face5 => self.total_5,
279 }
280 }
281
282 pub fn increment(&mut self, face: Face) {
284 match face {
285 Face::Face0 => self.total_0 += 1,
286 Face::Face1 => self.total_1 += 1,
287 Face::Face2 => self.total_2 += 1,
288 Face::Face3 => self.total_3 += 1,
289 Face::Face4 => self.total_4 += 1,
290 Face::Face5 => self.total_5 += 1,
291 }
292 self.total += 1;
293 }
294}
295
296pub type Attributions = BTreeMap<String, String>;
299
300#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
302pub struct FaceBounds {
303 #[serde(rename = "0")]
306 pub face0: BTreeMap<u8, TileBounds>,
307 #[serde(rename = "1")]
309 pub face1: BTreeMap<u8, TileBounds>,
310 #[serde(rename = "2")]
312 pub face2: BTreeMap<u8, TileBounds>,
313 #[serde(rename = "3")]
315 pub face3: BTreeMap<u8, TileBounds>,
316 #[serde(rename = "4")]
318 pub face4: BTreeMap<u8, TileBounds>,
319 #[serde(rename = "5")]
321 pub face5: BTreeMap<u8, TileBounds>,
322}
323impl FaceBounds {
324 pub fn get(&self, face: Face) -> &BTreeMap<u8, TileBounds> {
326 match face {
327 Face::Face0 => &self.face0,
328 Face::Face1 => &self.face1,
329 Face::Face2 => &self.face2,
330 Face::Face3 => &self.face3,
331 Face::Face4 => &self.face4,
332 Face::Face5 => &self.face5,
333 }
334 }
335
336 pub fn get_mut(&mut self, face: Face) -> &mut BTreeMap<u8, TileBounds> {
338 match face {
339 Face::Face0 => &mut self.face0,
340 Face::Face1 => &mut self.face1,
341 Face::Face2 => &mut self.face2,
342 Face::Face3 => &mut self.face3,
343 Face::Face4 => &mut self.face4,
344 Face::Face5 => &mut self.face5,
345 }
346 }
347}
348
349pub type WMBounds = BTreeMap<u8, TileBounds>;
352
353#[derive(Serialize, Debug, Default, Clone, PartialEq)]
355#[serde(rename_all = "lowercase")]
356pub enum SourceType {
357 #[default]
359 Vector,
360 Json,
362 Raster,
364 #[serde(rename = "raster-dem")]
366 RasterDem,
367 Grid,
369 Markers,
371 Unknown,
373}
374impl From<&str> for SourceType {
375 fn from(source_type: &str) -> Self {
376 match source_type {
377 "vector" => SourceType::Vector,
378 "json" => SourceType::Json,
379 "raster" => SourceType::Raster,
380 "raster-dem" => SourceType::RasterDem,
381 "grid" => SourceType::Grid,
382 "markers" => SourceType::Markers,
383 _ => SourceType::Unknown,
384 }
385 }
386}
387impl<'de> Deserialize<'de> for SourceType {
388 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
389 where
390 D: Deserializer<'de>,
391 {
392 let s: String = Deserialize::deserialize(deserializer)?;
394 Ok(SourceType::from(s.as_str()))
395 }
396}
397
398#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
400#[serde(rename_all = "lowercase")]
401pub enum Encoding {
402 #[default]
404 None = 0,
405 Gzip = 1,
407 #[serde(rename = "br")]
409 Brotli = 2,
410 Zstd = 3,
412}
413impl From<u8> for Encoding {
414 fn from(encoding: u8) -> Self {
415 match encoding {
416 1 => Encoding::Gzip,
417 2 => Encoding::Brotli,
418 3 => Encoding::Zstd,
419 _ => Encoding::None,
420 }
421 }
422}
423impl From<Encoding> for u8 {
424 fn from(encoding: Encoding) -> Self {
425 match encoding {
426 Encoding::Gzip => 1,
427 Encoding::Brotli => 2,
428 Encoding::Zstd => 3,
429 Encoding::None => 0,
430 }
431 }
432}
433impl From<Encoding> for &str {
434 fn from(encoding: Encoding) -> Self {
435 match encoding {
436 Encoding::Gzip => "gzip",
437 Encoding::Brotli => "br",
438 Encoding::Zstd => "zstd",
439 Encoding::None => "none",
440 }
441 }
442}
443impl From<&str> for Encoding {
444 fn from(encoding: &str) -> Self {
445 match encoding {
446 "gzip" => Encoding::Gzip,
447 "br" => Encoding::Brotli,
448 "zstd" => Encoding::Zstd,
449 _ => Encoding::None,
450 }
451 }
452}
453
454#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
456pub struct VectorLayer {
457 pub id: String,
459 #[serde(skip_serializing_if = "Option::is_none")]
461 pub description: Option<String>,
462 #[serde(skip_serializing_if = "Option::is_none")]
464 pub minzoom: Option<u8>,
465 #[serde(skip_serializing_if = "Option::is_none")]
467 pub maxzoom: Option<u8>,
468 pub fields: BTreeMap<String, String>,
470}
471
472#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
477#[serde(rename_all = "lowercase")]
478pub enum Scheme {
479 #[default]
481 Fzxy,
482 Tfzxy,
484 Xyz,
486 Txyz,
488 Tms,
490}
491impl From<&str> for Scheme {
492 fn from(scheme: &str) -> Self {
493 match scheme {
494 "fzxy" => Scheme::Fzxy,
495 "tfzxy" => Scheme::Tfzxy,
496 "xyz" => Scheme::Xyz,
497 "txyz" => Scheme::Txyz,
498 _ => Scheme::Tms,
499 }
500 }
501}
502impl From<Scheme> for &str {
503 fn from(scheme: Scheme) -> Self {
504 match scheme {
505 Scheme::Fzxy => "fzxy",
506 Scheme::Tfzxy => "tfzxy",
507 Scheme::Xyz => "xyz",
508 Scheme::Txyz => "txyz",
509 Scheme::Tms => "tms",
510 }
511 }
512}
513
514#[derive(Serialize, Deserialize, Debug, Default, Clone, PartialEq)]
516pub struct Center {
517 pub lon: f64,
519 pub lat: f64,
521 pub zoom: u8,
523}
524
525#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
539#[serde(default)]
540pub struct Metadata {
541 pub s2tilejson: String,
543 pub version: String,
545 pub name: String,
547 pub scheme: Scheme,
549 pub description: String,
551 #[serde(rename = "type")]
553 pub r#type: SourceType,
554 pub extension: String,
556 pub encoding: Encoding,
558 pub faces: Vec<Face>,
560 pub bounds: LonLatBounds,
562 pub wmbounds: WMBounds,
564 pub s2bounds: FaceBounds,
566 pub minzoom: u8,
568 pub maxzoom: u8,
570 pub centerpoint: Center,
572 pub attributions: Attributions,
574 pub layers: LayersMetaData,
576 pub tilestats: TileStatsMetadata,
578 pub vector_layers: Vec<VectorLayer>,
580
581 pub tilejson: Option<String>,
584 #[serde(skip_serializing_if = "Option::is_none")]
586 pub tiles: Option<Vec<String>>,
587 #[serde(skip_serializing_if = "Option::is_none")]
589 pub attribution: Option<String>,
590 #[serde(skip_serializing_if = "Option::is_none")]
592 pub fillzoom: Option<u8>,
593 #[serde(skip_serializing_if = "Option::is_none")]
595 pub center: Option<[f64; 3]>,
596 #[serde(skip_serializing_if = "Option::is_none")]
598 pub data: Option<Vec<String>>,
599 #[serde(skip_serializing_if = "Option::is_none")]
601 pub grids: Option<Vec<String>>,
602 #[serde(skip_serializing_if = "Option::is_none")]
604 pub legend: Option<String>,
605 #[serde(skip_serializing_if = "Option::is_none")]
607 pub template: Option<String>,
608}
609impl Default for Metadata {
610 fn default() -> Self {
611 Self {
612 s2tilejson: "1.0.0".into(),
613 version: "1.0.0".into(),
614 name: "default".into(),
615 scheme: Scheme::default(),
616 description: "Built with s2maps-cli".into(),
617 r#type: SourceType::default(),
618 extension: "pbf".into(),
619 encoding: Encoding::default(),
620 faces: Vec::default(),
621 bounds: BBox::new(-180.0, -90.0, 180.0, 90.0),
622 wmbounds: WMBounds::default(),
623 s2bounds: FaceBounds::default(),
624 minzoom: 0,
625 maxzoom: 27,
626 centerpoint: Center::default(),
627 attributions: BTreeMap::new(),
628 layers: LayersMetaData::default(),
629 tilestats: TileStatsMetadata::default(),
630 vector_layers: Vec::new(),
631 attribution: None,
632 fillzoom: None,
633 center: None,
634 data: None,
635 grids: None,
636 legend: None,
637 template: None,
638 tilejson: None,
639 tiles: None,
640 }
641 }
642}
643
644#[derive(Serialize, Deserialize, Debug, Clone, Default, PartialEq)]
659#[serde(default)]
660pub struct MapboxTileJSONMetadata {
661 pub tilejson: String,
663 pub tiles: Vec<String>,
665 pub vector_layers: Vec<VectorLayer>,
667 #[serde(skip_serializing_if = "Option::is_none")]
669 pub attribution: Option<String>,
670 #[serde(skip_serializing_if = "Option::is_none")]
672 pub bounds: Option<LonLatBounds>,
673 #[serde(skip_serializing_if = "Option::is_none")]
675 pub center: Option<[f64; 3]>,
676 #[serde(skip_serializing_if = "Option::is_none")]
678 pub data: Option<Vec<String>>,
679 #[serde(skip_serializing_if = "Option::is_none")]
681 pub description: Option<String>,
682 #[serde(skip_serializing_if = "Option::is_none")]
684 pub fillzoom: Option<u8>,
685 #[serde(skip_serializing_if = "Option::is_none")]
687 pub grids: Option<Vec<String>>,
688 #[serde(skip_serializing_if = "Option::is_none")]
690 pub legend: Option<String>,
691 #[serde(skip_serializing_if = "Option::is_none")]
693 pub maxzoom: Option<u8>,
694 #[serde(skip_serializing_if = "Option::is_none")]
696 pub minzoom: Option<u8>,
697 #[serde(skip_serializing_if = "Option::is_none")]
699 pub name: Option<String>,
700 #[serde(skip_serializing_if = "Option::is_none")]
702 pub scheme: Option<Scheme>,
703 #[serde(skip_serializing_if = "Option::is_none")]
705 pub template: Option<String>,
706 #[serde(skip_serializing_if = "Option::is_none")]
708 pub version: Option<String>,
709 #[serde(skip_serializing_if = "Option::is_none")]
712 pub r#type: Option<SourceType>,
713 #[serde(skip_serializing_if = "Option::is_none")]
715 pub extension: Option<String>,
716 #[serde(skip_serializing_if = "Option::is_none")]
718 pub encoding: Option<Encoding>,
719}
720impl MapboxTileJSONMetadata {
721 pub fn to_metadata(&self) -> Metadata {
723 let [lon, lat, zoom] = self.center.unwrap_or([0.0, 0.0, 0.0]);
724 Metadata {
725 s2tilejson: "1.0.0".into(),
726 version: self.version.clone().unwrap_or("1.0.0".into()),
727 name: self.name.clone().unwrap_or("default".into()),
728 scheme: self.scheme.clone().unwrap_or_default(),
729 description: self.description.clone().unwrap_or("Built with s2maps-cli".into()),
730 r#type: self.r#type.clone().unwrap_or_default(),
731 extension: self.extension.clone().unwrap_or("pbf".into()),
732 faces: Vec::from([Face::Face0]),
733 bounds: self.bounds.unwrap_or_default(),
734 minzoom: self.minzoom.unwrap_or(0),
735 maxzoom: self.maxzoom.unwrap_or(27),
736 centerpoint: Center { lon, lat, zoom: zoom as u8 },
737 center: Some([lon, lat, zoom]),
738 attributions: extract_link_info(self.attribution.as_ref().unwrap_or(&"".into()))
739 .unwrap_or_default(),
740 vector_layers: self.vector_layers.clone(),
741 encoding: self.encoding.clone().unwrap_or(Encoding::None),
742 attribution: self.attribution.clone(),
743 tiles: Some(self.tiles.clone()),
744 data: self.data.clone(),
745 grids: self.grids.clone(),
746 legend: self.legend.clone(),
747 template: self.template.clone(),
748 fillzoom: self.fillzoom,
749 ..Default::default()
750 }
751 }
752}
753
754#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
756#[serde(untagged)]
757pub enum UnknownMetadata {
758 Metadata(Box<Metadata>),
760 Mapbox(Box<MapboxTileJSONMetadata>),
762}
763impl UnknownMetadata {
764 pub fn to_metadata(&self) -> Metadata {
766 match self {
767 UnknownMetadata::Metadata(m) => *m.clone(),
768 UnknownMetadata::Mapbox(m) => m.to_metadata(),
769 }
770 }
771}
772
773#[derive(Debug, Clone)]
797pub struct MetadataBuilder {
798 lon_lat_bounds: LonLatBounds,
799 faces: BTreeSet<Face>,
800 metadata: Metadata,
801}
802impl Default for MetadataBuilder {
803 fn default() -> Self {
804 MetadataBuilder {
805 lon_lat_bounds: BBox {
806 left: f64::INFINITY,
807 bottom: f64::INFINITY,
808 right: -f64::INFINITY,
809 top: -f64::INFINITY,
810 },
811 faces: BTreeSet::new(),
812 metadata: Metadata { minzoom: 30, maxzoom: 0, ..Metadata::default() },
813 }
814 }
815}
816impl MetadataBuilder {
817 pub fn commit(&mut self) -> Metadata {
819 self.update_center();
821 self.metadata.bounds = self.lon_lat_bounds;
823 for face in &self.faces {
825 self.metadata.faces.push(*face);
826 }
827 self.metadata.to_owned()
829 }
830
831 pub fn set_name(&mut self, name: String) {
833 self.metadata.name = name;
834 }
835
836 pub fn set_scheme(&mut self, scheme: Scheme) {
838 self.metadata.scheme = scheme;
839 }
840
841 pub fn set_extension(&mut self, extension: String) {
843 self.metadata.extension = extension;
844 }
845
846 pub fn set_type(&mut self, r#type: SourceType) {
848 self.metadata.r#type = r#type;
849 }
850
851 pub fn set_version(&mut self, version: String) {
853 self.metadata.version = version;
854 }
855
856 pub fn set_description(&mut self, description: String) {
858 self.metadata.description = description;
859 }
860
861 pub fn set_encoding(&mut self, encoding: Encoding) {
863 self.metadata.encoding = encoding;
864 }
865
866 pub fn add_attribution(&mut self, display_name: &str, href: &str) {
868 self.metadata.attributions.insert(display_name.into(), href.into());
869 }
870
871 pub fn add_layer(&mut self, name: &str, layer: &LayerMetaData) {
873 if self.metadata.layers.entry(name.into()).or_insert(layer.clone()).eq(&layer) {
875 self.metadata.vector_layers.push(VectorLayer {
877 id: name.into(), description: layer.description.clone(),
879 minzoom: Some(layer.minzoom),
880 maxzoom: Some(layer.maxzoom),
881 fields: BTreeMap::new(),
882 });
883 }
884 if layer.minzoom < self.metadata.minzoom {
886 self.metadata.minzoom = layer.minzoom;
887 }
888 if layer.maxzoom > self.metadata.maxzoom {
889 self.metadata.maxzoom = layer.maxzoom;
890 }
891 }
892
893 pub fn add_tile_wm(&mut self, zoom: u8, x: u32, y: u32, ll_bounds: &LonLatBounds) {
895 self.metadata.tilestats.total += 1;
896 self.faces.insert(Face::Face0);
897 self.add_bounds_wm(zoom, x, y);
898 self.update_lon_lat_bounds(ll_bounds);
899 }
900
901 pub fn add_tile_s2(&mut self, face: Face, zoom: u8, x: u32, y: u32, ll_bounds: &LonLatBounds) {
903 self.metadata.tilestats.increment(face);
904 self.faces.insert(face);
905 self.add_bounds_s2(face, zoom, x, y);
906 self.update_lon_lat_bounds(ll_bounds);
907 }
908
909 fn update_center(&mut self) {
911 let Metadata { minzoom, maxzoom, .. } = self.metadata;
912 let BBox { left, bottom, right, top } = self.lon_lat_bounds;
913 self.metadata.centerpoint.lon = (left + right) / 2.0;
914 self.metadata.centerpoint.lat = (bottom + top) / 2.0;
915 self.metadata.centerpoint.zoom = (minzoom + maxzoom) >> 1;
916 }
917
918 fn add_bounds_wm(&mut self, zoom: u8, x: u32, y: u32) {
920 let x = x as u64;
921 let y = y as u64;
922 let bbox = self.metadata.wmbounds.entry(zoom).or_insert(BBox {
923 left: u64::MAX,
924 bottom: u64::MAX,
925 right: 0,
926 top: 0,
927 });
928
929 bbox.left = bbox.left.min(x);
930 bbox.bottom = bbox.bottom.min(y);
931 bbox.right = bbox.right.max(x);
932 bbox.top = bbox.top.max(y);
933 }
934
935 fn add_bounds_s2(&mut self, face: Face, zoom: u8, x: u32, y: u32) {
937 let x = x as u64;
938 let y = y as u64;
939 let bbox = self.metadata.s2bounds.get_mut(face).entry(zoom).or_insert(BBox {
940 left: u64::MAX,
941 bottom: u64::MAX,
942 right: 0,
943 top: 0,
944 });
945
946 bbox.left = bbox.left.min(x);
947 bbox.bottom = bbox.bottom.min(y);
948 bbox.right = bbox.right.max(x);
949 bbox.top = bbox.top.max(y);
950 }
951
952 fn update_lon_lat_bounds(&mut self, ll_bounds: &LonLatBounds) {
954 self.lon_lat_bounds.left = ll_bounds.left.min(self.lon_lat_bounds.left);
955 self.lon_lat_bounds.bottom = ll_bounds.bottom.min(self.lon_lat_bounds.bottom);
956 self.lon_lat_bounds.right = ll_bounds.right.max(self.lon_lat_bounds.right);
957 self.lon_lat_bounds.top = ll_bounds.top.max(self.lon_lat_bounds.top);
958 }
959}
960
961fn extract_link_info(html_string: &str) -> Option<Attributions> {
963 let href_start = html_string.find("href='")?;
965 let href_value_start = href_start + "href='".len();
966 let href_end = html_string[href_value_start..].find("'")?;
967 let href_value = &html_string[href_value_start..href_value_start + href_end];
968
969 let text_start = html_string.find(">")?;
971 let text_value_start = text_start + 1;
972 let text_end = html_string.find("</a>")?;
973 let text_value = &html_string[text_value_start..text_end];
974
975 let mut map = BTreeMap::new();
976 map.insert(text_value.into(), href_value.into());
977
978 Some(map)
979}
980
981#[cfg(test)]
982mod tests {
983 use super::*;
984 use alloc::vec;
985 use s2json::{PrimitiveShape, ShapeType};
986
987 #[test]
988 fn it_works() {
989 let mut meta_builder = MetadataBuilder::default();
990
991 meta_builder.set_name("OSM".into());
993 meta_builder.set_description("A free editable map of the whole world.".into());
994 meta_builder.set_version("1.0.0".into());
995 meta_builder.set_scheme("fzxy".into()); meta_builder.set_type("vector".into()); meta_builder.set_encoding("none".into()); meta_builder.set_extension("pbf".into());
999 meta_builder.add_attribution("OpenStreetMap", "https://www.openstreetmap.org/copyright/");
1000
1001 let shape_str = r#"
1003 {
1004 "class": "string",
1005 "offset": "f64",
1006 "info": {
1007 "name": "string",
1008 "value": "i64"
1009 }
1010 }
1011 "#;
1012 let shape: Shape = serde_json::from_str(shape_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1013 let layer = LayerMetaData {
1014 minzoom: 0,
1015 maxzoom: 13,
1016 description: Some("water_lines".into()),
1017 draw_types: Vec::from(&[DrawType::Lines]),
1018 shape: shape.clone(),
1019 m_shape: None,
1020 };
1021 meta_builder.add_layer("water_lines", &layer);
1022
1023 meta_builder.add_tile_wm(
1026 0,
1027 0,
1028 0,
1029 &LonLatBounds { left: -60.0, bottom: -20.0, right: 5.0, top: 60.0 },
1030 );
1031 meta_builder.add_tile_s2(
1033 Face::Face1,
1034 5,
1035 22,
1036 37,
1037 &LonLatBounds { left: -120.0, bottom: -7.0, right: 44.0, top: 72.0 },
1038 );
1039
1040 let resulting_metadata: Metadata = meta_builder.commit();
1042
1043 assert_eq!(
1044 resulting_metadata,
1045 Metadata {
1046 name: "OSM".into(),
1047 description: "A free editable map of the whole world.".into(),
1048 version: "1.0.0".into(),
1049 scheme: "fzxy".into(),
1050 r#type: "vector".into(),
1051 encoding: "none".into(),
1052 extension: "pbf".into(),
1053 attributions: BTreeMap::from([(
1054 "OpenStreetMap".into(),
1055 "https://www.openstreetmap.org/copyright/".into()
1056 ),]),
1057 wmbounds: BTreeMap::from([(
1058 0,
1059 TileBounds { left: 0, bottom: 0, right: 0, top: 0 }
1060 ),]),
1061 faces: Vec::from(&[Face::Face0, Face::Face1]),
1062 bounds: BBox { left: -120.0, bottom: -20.0, right: 44.0, top: 72.0 },
1063 s2bounds: FaceBounds {
1064 face0: BTreeMap::new(),
1065 face1: BTreeMap::from([(
1066 5,
1067 TileBounds { left: 22, bottom: 37, right: 22, top: 37 }
1068 ),]),
1069 face2: BTreeMap::new(),
1070 face3: BTreeMap::new(),
1071 face4: BTreeMap::new(),
1072 face5: BTreeMap::new(),
1073 },
1074 minzoom: 0,
1075 maxzoom: 13,
1076 centerpoint: Center { lon: -38.0, lat: 26.0, zoom: 6 },
1078 tilestats: TileStatsMetadata {
1079 total: 2,
1080 total_0: 0,
1081 total_1: 1,
1082 total_2: 0,
1083 total_3: 0,
1084 total_4: 0,
1085 total_5: 0,
1086 },
1087 layers: BTreeMap::from([(
1088 "water_lines".into(),
1089 LayerMetaData {
1090 description: Some("water_lines".into()),
1091 minzoom: 0,
1092 maxzoom: 13,
1093 draw_types: Vec::from(&[DrawType::Lines]),
1094 shape: Shape::from([
1095 ("class".into(), ShapeType::Primitive(PrimitiveShape::String)),
1096 ("offset".into(), ShapeType::Primitive(PrimitiveShape::F64)),
1097 (
1098 "info".into(),
1099 ShapeType::Nested(Shape::from([
1100 ("name".into(), ShapeType::Primitive(PrimitiveShape::String)),
1101 ("value".into(), ShapeType::Primitive(PrimitiveShape::I64)),
1102 ]))
1103 ),
1104 ]),
1105 m_shape: None,
1106 }
1107 )]),
1108 s2tilejson: "1.0.0".into(),
1109 vector_layers: Vec::from([VectorLayer {
1110 id: "water_lines".into(),
1111 description: Some("water_lines".into()),
1112 minzoom: Some(0),
1113 maxzoom: Some(13),
1114 fields: BTreeMap::new()
1115 }]),
1116 ..Default::default()
1117 }
1118 );
1119
1120 let meta_str = serde_json::to_string(&resulting_metadata).unwrap();
1121
1122 assert_eq!(
1123 meta_str,
1124 "{\"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}"
1125 );
1126
1127 let meta_reparsed: Metadata =
1128 serde_json::from_str(&meta_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1129 assert_eq!(meta_reparsed, resulting_metadata);
1130 }
1131
1132 #[test]
1133 fn test_face() {
1134 assert_eq!(Face::Face0, Face::from(0));
1135 assert_eq!(Face::Face1, Face::from(1));
1136 assert_eq!(Face::Face2, Face::from(2));
1137 assert_eq!(Face::Face3, Face::from(3));
1138 assert_eq!(Face::Face4, Face::from(4));
1139 assert_eq!(Face::Face5, Face::from(5));
1140
1141 assert_eq!(0, u8::from(Face::Face0));
1142 assert_eq!(1, u8::from(Face::Face1));
1143 assert_eq!(2, u8::from(Face::Face2));
1144 assert_eq!(3, u8::from(Face::Face3));
1145 assert_eq!(4, u8::from(Face::Face4));
1146 assert_eq!(5, u8::from(Face::Face5));
1147 }
1148
1149 #[test]
1150 fn test_bbox() {
1151 let bbox: BBox = BBox { left: 0.0, bottom: 0.0, right: 0.0, top: 0.0 };
1152 let json = serde_json::to_string(&bbox).unwrap();
1154 assert_eq!(json, r#"[0.0,0.0,0.0,0.0]"#);
1155 let bbox2: BBox = serde_json::from_str(&json).unwrap();
1156 assert_eq!(bbox, bbox2);
1157 }
1158
1159 #[test]
1161 fn test_tilestats() {
1162 let mut tilestats = TileStatsMetadata {
1163 total: 2,
1164 total_0: 0,
1165 total_1: 1,
1166 total_2: 0,
1167 total_3: 0,
1168 total_4: 0,
1169 total_5: 0,
1170 };
1171 let json = serde_json::to_string(&tilestats).unwrap();
1173 assert_eq!(json, r#"{"total":2,"0":0,"1":1,"2":0,"3":0,"4":0,"5":0}"#);
1174 let tilestats2: TileStatsMetadata = serde_json::from_str(&json).unwrap();
1175 assert_eq!(tilestats, tilestats2);
1176
1177 assert_eq!(tilestats.get(0.into()), 0);
1179 tilestats.increment(0.into());
1181 assert_eq!(tilestats.get(0.into()), 1);
1182
1183 assert_eq!(tilestats.get(1.into()), 1);
1185 tilestats.increment(1.into());
1187 assert_eq!(tilestats.get(1.into()), 2);
1188
1189 assert_eq!(tilestats.get(2.into()), 0);
1191 tilestats.increment(2.into());
1193 assert_eq!(tilestats.get(2.into()), 1);
1194
1195 assert_eq!(tilestats.get(3.into()), 0);
1197 tilestats.increment(3.into());
1199 assert_eq!(tilestats.get(3.into()), 1);
1200
1201 assert_eq!(tilestats.get(4.into()), 0);
1203 tilestats.increment(4.into());
1205 assert_eq!(tilestats.get(4.into()), 1);
1206
1207 assert_eq!(tilestats.get(5.into()), 0);
1209 tilestats.increment(5.into());
1211 assert_eq!(tilestats.get(5.into()), 1);
1212 }
1213
1214 #[test]
1216 fn test_facebounds() {
1217 let mut facebounds = FaceBounds::default();
1218 let face0 = facebounds.get_mut(0.into());
1220 face0.insert(0, TileBounds { left: 0, bottom: 0, right: 0, top: 0 });
1221 let face1 = facebounds.get_mut(1.into());
1223 face1.insert(0, TileBounds { left: 0, bottom: 0, right: 1, top: 1 });
1224 let face2 = facebounds.get_mut(2.into());
1226 face2.insert(0, TileBounds { left: 0, bottom: 0, right: 2, top: 2 });
1227 let face3 = facebounds.get_mut(3.into());
1229 face3.insert(0, TileBounds { left: 0, bottom: 0, right: 3, top: 3 });
1230 let face4 = facebounds.get_mut(4.into());
1232 face4.insert(0, TileBounds { left: 0, bottom: 0, right: 4, top: 4 });
1233 let face5 = facebounds.get_mut(5.into());
1235 face5.insert(0, TileBounds { left: 0, bottom: 0, right: 5, top: 5 });
1236
1237 assert_eq!(
1240 facebounds.get(0.into()).get(&0).unwrap(),
1241 &TileBounds { left: 0, bottom: 0, right: 0, top: 0 }
1242 );
1243 assert_eq!(
1245 facebounds.get(1.into()).get(&0).unwrap(),
1246 &TileBounds { left: 0, bottom: 0, right: 1, top: 1 }
1247 );
1248 assert_eq!(
1250 facebounds.get(2.into()).get(&0).unwrap(),
1251 &TileBounds { left: 0, bottom: 0, right: 2, top: 2 }
1252 );
1253 assert_eq!(
1255 facebounds.get(3.into()).get(&0).unwrap(),
1256 &TileBounds { left: 0, bottom: 0, right: 3, top: 3 }
1257 );
1258 assert_eq!(
1260 facebounds.get(4.into()).get(&0).unwrap(),
1261 &TileBounds { left: 0, bottom: 0, right: 4, top: 4 }
1262 );
1263 assert_eq!(
1265 facebounds.get(5.into()).get(&0).unwrap(),
1266 &TileBounds { left: 0, bottom: 0, right: 5, top: 5 }
1267 );
1268
1269 let json = serde_json::to_string(&facebounds).unwrap();
1271 assert_eq!(
1272 json,
1273 "{\"0\":{\"0\":[0,0,0,0]},\"1\":{\"0\":[0,0,1,1]},\"2\":{\"0\":[0,0,2,2]},\"3\":{\"0\"\
1274 :[0,0,3,3]},\"4\":{\"0\":[0,0,4,4]},\"5\":{\"0\":[0,0,5,5]}}"
1275 );
1276 let facebounds2 = serde_json::from_str(&json).unwrap();
1277 assert_eq!(facebounds, facebounds2);
1278 }
1279
1280 #[test]
1282 fn test_drawtype() {
1283 assert_eq!(DrawType::from(1), DrawType::Points);
1284 assert_eq!(DrawType::from(2), DrawType::Lines);
1285 assert_eq!(DrawType::from(3), DrawType::Polygons);
1286 assert_eq!(DrawType::from(4), DrawType::Points3D);
1287 assert_eq!(DrawType::from(5), DrawType::Lines3D);
1288 assert_eq!(DrawType::from(6), DrawType::Polygons3D);
1289 assert_eq!(DrawType::from(7), DrawType::Raster);
1290 assert_eq!(DrawType::from(8), DrawType::Grid);
1291
1292 assert_eq!(1, u8::from(DrawType::Points));
1293 assert_eq!(2, u8::from(DrawType::Lines));
1294 assert_eq!(3, u8::from(DrawType::Polygons));
1295 assert_eq!(4, u8::from(DrawType::Points3D));
1296 assert_eq!(5, u8::from(DrawType::Lines3D));
1297 assert_eq!(6, u8::from(DrawType::Polygons3D));
1298 assert_eq!(7, u8::from(DrawType::Raster));
1299 assert_eq!(8, u8::from(DrawType::Grid));
1300
1301 let json = serde_json::to_string(&DrawType::Points).unwrap();
1303 assert_eq!(json, "1");
1304 let drawtype: DrawType = serde_json::from_str(&json).unwrap();
1305 assert_eq!(drawtype, DrawType::Points);
1306
1307 let drawtype: DrawType = serde_json::from_str("2").unwrap();
1308 assert_eq!(drawtype, DrawType::Lines);
1309
1310 let drawtype: DrawType = serde_json::from_str("3").unwrap();
1311 assert_eq!(drawtype, DrawType::Polygons);
1312
1313 let drawtype: DrawType = serde_json::from_str("4").unwrap();
1314 assert_eq!(drawtype, DrawType::Points3D);
1315
1316 let drawtype: DrawType = serde_json::from_str("5").unwrap();
1317 assert_eq!(drawtype, DrawType::Lines3D);
1318
1319 let drawtype: DrawType = serde_json::from_str("6").unwrap();
1320 assert_eq!(drawtype, DrawType::Polygons3D);
1321
1322 let drawtype: DrawType = serde_json::from_str("7").unwrap();
1323 assert_eq!(drawtype, DrawType::Raster);
1324
1325 let drawtype: DrawType = serde_json::from_str("8").unwrap();
1326 assert_eq!(drawtype, DrawType::Grid);
1327
1328 assert!(serde_json::from_str::<DrawType>("9").is_err());
1329 }
1330
1331 #[test]
1333 fn test_sourcetype() {
1334 assert_eq!(SourceType::from("vector"), SourceType::Vector);
1336 assert_eq!(SourceType::from("json"), SourceType::Json);
1337 assert_eq!(SourceType::from("raster"), SourceType::Raster);
1338 assert_eq!(SourceType::from("raster-dem"), SourceType::RasterDem);
1339 assert_eq!(SourceType::from("grid"), SourceType::Grid);
1340 assert_eq!(SourceType::from("markers"), SourceType::Markers);
1341 assert_eq!(SourceType::from("overlay"), SourceType::Unknown);
1342
1343 let json = serde_json::to_string(&SourceType::Vector).unwrap();
1345 assert_eq!(json, "\"vector\"");
1346 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1347 assert_eq!(sourcetype, SourceType::Vector);
1348
1349 let json = serde_json::to_string(&SourceType::Json).unwrap();
1351 assert_eq!(json, "\"json\"");
1352 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1353 assert_eq!(sourcetype, SourceType::Json);
1354
1355 let json = serde_json::to_string(&SourceType::Raster).unwrap();
1357 assert_eq!(json, "\"raster\"");
1358 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1359 assert_eq!(sourcetype, SourceType::Raster);
1360
1361 let json = serde_json::to_string(&SourceType::RasterDem).unwrap();
1363 assert_eq!(json, "\"raster-dem\"");
1364 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1365 assert_eq!(sourcetype, SourceType::RasterDem);
1366
1367 let json = serde_json::to_string(&SourceType::Grid).unwrap();
1369 assert_eq!(json, "\"grid\"");
1370 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1371 assert_eq!(sourcetype, SourceType::Grid);
1372
1373 let json = serde_json::to_string(&SourceType::Markers).unwrap();
1375 assert_eq!(json, "\"markers\"");
1376 let sourcetype: SourceType = serde_json::from_str(&json).unwrap();
1377 assert_eq!(sourcetype, SourceType::Markers);
1378
1379 let json = serde_json::to_string(&SourceType::Unknown).unwrap();
1381 assert_eq!(json, "\"unknown\"");
1382 let sourcetype: SourceType = serde_json::from_str(r#""overlay""#).unwrap();
1383 assert_eq!(sourcetype, SourceType::Unknown);
1384 }
1385
1386 #[test]
1388 fn test_encoding() {
1389 assert_eq!(Encoding::from("none"), Encoding::None);
1391 assert_eq!(Encoding::from("gzip"), Encoding::Gzip);
1392 assert_eq!(Encoding::from("br"), Encoding::Brotli);
1393 assert_eq!(Encoding::from("zstd"), Encoding::Zstd);
1394
1395 assert_eq!(core::convert::Into::<&str>::into(Encoding::None), "none");
1397 assert_eq!(core::convert::Into::<&str>::into(Encoding::Gzip), "gzip");
1398 assert_eq!(core::convert::Into::<&str>::into(Encoding::Brotli), "br");
1399 assert_eq!(core::convert::Into::<&str>::into(Encoding::Zstd), "zstd");
1400
1401 assert_eq!(Encoding::from(0), Encoding::None);
1403 assert_eq!(Encoding::from(1), Encoding::Gzip);
1404 assert_eq!(Encoding::from(2), Encoding::Brotli);
1405 assert_eq!(Encoding::from(3), Encoding::Zstd);
1406
1407 assert_eq!(u8::from(Encoding::None), 0);
1409 assert_eq!(u8::from(Encoding::Gzip), 1);
1410 assert_eq!(u8::from(Encoding::Brotli), 2);
1411 assert_eq!(u8::from(Encoding::Zstd), 3);
1412
1413 let json = serde_json::to_string(&Encoding::Gzip).unwrap();
1415 assert_eq!(json, "\"gzip\"");
1416 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1417 assert_eq!(encoding, Encoding::Gzip);
1418
1419 let json = serde_json::to_string(&Encoding::Brotli).unwrap();
1421 assert_eq!(json, "\"br\"");
1422 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1423 assert_eq!(encoding, Encoding::Brotli);
1424
1425 let json = serde_json::to_string(&Encoding::None).unwrap();
1427 assert_eq!(json, "\"none\"");
1428 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1429 assert_eq!(encoding, Encoding::None);
1430
1431 let json = serde_json::to_string(&Encoding::Zstd).unwrap();
1433 assert_eq!(json, "\"zstd\"");
1434 let encoding: Encoding = serde_json::from_str(&json).unwrap();
1435 assert_eq!(encoding, Encoding::Zstd);
1436 }
1437
1438 #[test]
1440 fn test_scheme() {
1441 assert_eq!(Scheme::from("fzxy"), Scheme::Fzxy);
1443 assert_eq!(Scheme::from("tfzxy"), Scheme::Tfzxy);
1444 assert_eq!(Scheme::from("xyz"), Scheme::Xyz);
1445 assert_eq!(Scheme::from("txyz"), Scheme::Txyz);
1446 assert_eq!(Scheme::from("tms"), Scheme::Tms);
1447
1448 assert_eq!(core::convert::Into::<&str>::into(Scheme::Fzxy), "fzxy");
1450 assert_eq!(core::convert::Into::<&str>::into(Scheme::Tfzxy), "tfzxy");
1451 assert_eq!(core::convert::Into::<&str>::into(Scheme::Xyz), "xyz");
1452 assert_eq!(core::convert::Into::<&str>::into(Scheme::Txyz), "txyz");
1453 assert_eq!(core::convert::Into::<&str>::into(Scheme::Tms), "tms");
1454 }
1455
1456 #[test]
1457 fn test_tippecanoe_metadata() {
1458 let meta_str = r#"{
1459 "name": "test_fixture_1.pmtiles",
1460 "description": "test_fixture_1.pmtiles",
1461 "version": "2",
1462 "type": "overlay",
1463 "generator": "tippecanoe v2.5.0",
1464 "generator_options": "./tippecanoe -zg -o test_fixture_1.pmtiles --force",
1465 "vector_layers": [
1466 {
1467 "id": "test_fixture_1pmtiles",
1468 "description": "",
1469 "minzoom": 0,
1470 "maxzoom": 0,
1471 "fields": {}
1472 }
1473 ],
1474 "tilestats": {
1475 "layerCount": 1,
1476 "layers": [
1477 {
1478 "layer": "test_fixture_1pmtiles",
1479 "count": 1,
1480 "geometry": "Polygon",
1481 "attributeCount": 0,
1482 "attributes": []
1483 }
1484 ]
1485 }
1486 }"#;
1487
1488 let _meta: Metadata =
1489 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1490 }
1491
1492 #[test]
1493 fn test_mapbox_metadata() {
1494 let meta_str = r#"{
1495 "tilejson": "3.0.0",
1496 "name": "OpenStreetMap",
1497 "description": "A free editable map of the whole world.",
1498 "version": "1.0.0",
1499 "attribution": "<a href='https://openstreetmap.org'>OSM contributors</a>",
1500 "scheme": "xyz",
1501 "tiles": [
1502 "https://a.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt",
1503 "https://b.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt",
1504 "https://c.tile.custom-osm-tiles.org/{z}/{x}/{y}.mvt"
1505 ],
1506 "minzoom": 0,
1507 "maxzoom": 18,
1508 "bounds": [-180, -85, 180, 85],
1509 "fillzoom": 6,
1510 "something_custom": "this is my unique field",
1511 "vector_layers": [
1512 {
1513 "id": "telephone",
1514 "fields": {
1515 "phone_number": "the phone number",
1516 "payment": "how to pay"
1517 }
1518 },
1519 {
1520 "id": "bicycle_parking",
1521 "fields": {
1522 "type": "the type of bike parking",
1523 "year_installed": "the year the bike parking was installed"
1524 }
1525 },
1526 {
1527 "id": "showers",
1528 "fields": {
1529 "water_temperature": "the maximum water temperature",
1530 "wear_sandles": "whether you should wear sandles or not",
1531 "wheelchair": "is the shower wheelchair friendly?"
1532 }
1533 }
1534 ]
1535 }"#;
1536
1537 let meta_mapbox: MapboxTileJSONMetadata =
1538 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1539 let meta_new = meta_mapbox.to_metadata();
1540 assert_eq!(
1541 meta_new,
1542 Metadata {
1543 name: "OpenStreetMap".into(),
1544 description: "A free editable map of the whole world.".into(),
1545 version: "1.0.0".into(),
1546 scheme: Scheme::Xyz,
1547 r#type: "vector".into(),
1548 encoding: Encoding::None, extension: "pbf".into(),
1550 attributions: BTreeMap::from([(
1551 "OSM contributors".into(),
1552 "https://openstreetmap.org".into()
1553 )]),
1554 bounds: BBox::new(-180., -85., 180., 85.),
1555 vector_layers: meta_mapbox.vector_layers.clone(),
1556 maxzoom: 18,
1557 minzoom: 0,
1558 centerpoint: Center { lat: 0.0, lon: 0.0, zoom: 0 },
1559 wmbounds: WMBounds::default(),
1560 faces: vec![Face::Face0],
1561 s2bounds: FaceBounds::default(),
1562 tilestats: TileStatsMetadata::default(),
1563 layers: LayersMetaData::default(),
1564 s2tilejson: "1.0.0".into(),
1565 attribution: Some(
1566 "<a href='https://openstreetmap.org'>OSM contributors</a>".into()
1567 ),
1568 tiles: Some(meta_mapbox.tiles.clone()),
1569 fillzoom: meta_mapbox.fillzoom,
1570 center: Some([0.0, 0.0, 0.0]),
1571 ..Default::default()
1572 },
1573 );
1574
1575 let meta_mapbox_from_unknown: UnknownMetadata =
1576 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1577 let meta_new = meta_mapbox_from_unknown.to_metadata();
1578 assert_eq!(
1579 meta_new,
1580 Metadata {
1581 name: "OpenStreetMap".into(),
1582 description: "A free editable map of the whole world.".into(),
1583 version: "1.0.0".into(),
1584 scheme: Scheme::Xyz,
1585 r#type: "vector".into(),
1586 encoding: Encoding::None, extension: "pbf".into(),
1588 attributions: BTreeMap::default(),
1589 bounds: BBox::new(-180., -85., 180., 85.),
1590 vector_layers: meta_mapbox.vector_layers.clone(),
1591 maxzoom: 18,
1592 minzoom: 0,
1593 centerpoint: Center { lat: 0.0, lon: 0.0, zoom: 0 },
1594 wmbounds: WMBounds::default(),
1595 faces: vec![],
1596 s2bounds: FaceBounds::default(),
1597 tilestats: TileStatsMetadata::default(),
1598 layers: LayersMetaData::default(),
1599 s2tilejson: "1.0.0".into(),
1600 attribution: Some(
1601 "<a href='https://openstreetmap.org'>OSM contributors</a>".into()
1602 ),
1603 tiles: Some(meta_mapbox.tiles.clone()),
1604 fillzoom: meta_mapbox.fillzoom,
1605 center: None,
1606 tilejson: Some("3.0.0".into()),
1607 ..Default::default()
1608 },
1609 );
1610 }
1611
1612 #[test]
1613 fn test_malformed_metadata() {
1614 let meta_str = r#"{
1615 "s2tilejson": "1.0.0",
1616 "bounds": [
1617 -180,
1618 -85,
1619 180,
1620 85
1621 ],
1622 "name": "Mapbox Satellite",
1623 "scheme": "xyz",
1624 "format": "zxy",
1625 "type": "raster",
1626 "extension": "webp",
1627 "encoding": "gzip",
1628 "minzoom": 0,
1629 "maxzoom": 3
1630 }
1631 "#;
1632
1633 let malformed_success: UnknownMetadata =
1634 serde_json::from_str(meta_str).unwrap_or_else(|e| panic!("ERROR: {e}"));
1635
1636 let meta: Metadata = malformed_success.to_metadata();
1637 assert_eq!(
1638 meta,
1639 Metadata {
1640 s2tilejson: "1.0.0".into(),
1641 version: "1.0.0".into(),
1642 name: "Mapbox Satellite".into(),
1643 scheme: Scheme::Xyz,
1644 description: "Built with s2maps-cli".into(),
1645 r#type: SourceType::Raster,
1646 extension: "webp".into(),
1647 encoding: Encoding::Gzip,
1648 faces: vec![],
1649 bounds: BBox::new(-180., -85., 180., 85.),
1650 wmbounds: BTreeMap::default(),
1651 s2bounds: FaceBounds {
1652 face0: BTreeMap::default(),
1653 face1: BTreeMap::default(),
1654 face2: BTreeMap::default(),
1655 face3: BTreeMap::default(),
1656 face4: BTreeMap::default(),
1657 face5: BTreeMap::default()
1658 },
1659 minzoom: 0,
1660 maxzoom: 3,
1661 centerpoint: Center { lon: 0.0, lat: 0.0, zoom: 0 },
1662 attributions: BTreeMap::default(),
1663 layers: BTreeMap::default(),
1664 tilestats: TileStatsMetadata {
1665 total: 0,
1666 total_0: 0,
1667 total_1: 0,
1668 total_2: 0,
1669 total_3: 0,
1670 total_4: 0,
1671 total_5: 0
1672 },
1673 vector_layers: vec![],
1674 ..Default::default()
1675 }
1676 );
1677 }
1678
1679 #[test]
1680 fn test_faces() {
1681 let meta = Metadata {
1682 faces: vec![Face::Face0, Face::Face1, Face::Face4, Face::Face5],
1683 ..Default::default()
1684 };
1685
1686 let to_string: String = serde_json::to_string(&meta).unwrap();
1687 let from_string: Metadata = serde_json::from_str(&to_string).unwrap();
1688 assert_eq!(meta, from_string);
1689
1690 let from_string_unknown: UnknownMetadata = serde_json::from_str(&to_string).unwrap();
1691 let from_string: Metadata = from_string_unknown.to_metadata();
1692 assert_eq!(meta, from_string);
1693 }
1694
1695 #[test]
1696 fn test_vector_feature_to_draw_type() {
1697 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1699 geometry: VectorGeometry::new_point(VectorPoint::from_xy(0., 0.), None),
1700 ..Default::default()
1701 };
1702 assert_eq!(DrawType::Points, (&feature).into());
1703 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1704 geometry: VectorGeometry::new_multipoint(vec![VectorPoint::from_xy(0., 0.)], None),
1705 ..Default::default()
1706 };
1707 assert_eq!(DrawType::Points, (&feature).into());
1708 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1710 geometry: VectorGeometry::new_point(VectorPoint::from_xyz(0., 0., 1.0), None),
1711 ..Default::default()
1712 };
1713 assert_eq!(DrawType::Points3D, (&feature).into());
1714 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1715 geometry: VectorGeometry::new_multipoint(
1716 vec![VectorPoint::from_xyz(0., 0., 1.0)],
1717 None,
1718 ),
1719 ..Default::default()
1720 };
1721 assert_eq!(DrawType::Points3D, (&feature).into());
1722 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1724 geometry: VectorGeometry::new_linestring(vec![VectorPoint::from_xy(0., 0.)], None),
1725 ..Default::default()
1726 };
1727 assert_eq!(DrawType::Lines, (&feature).into());
1728 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1729 geometry: VectorGeometry::new_multilinestring(
1730 vec![vec![VectorPoint::from_xy(0., 0.)]],
1731 None,
1732 ),
1733 ..Default::default()
1734 };
1735 assert_eq!(DrawType::Lines, (&feature).into());
1736 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1738 geometry: VectorGeometry::new_linestring(
1739 vec![VectorPoint::from_xyz(0., 0., 1.0)],
1740 None,
1741 ),
1742 ..Default::default()
1743 };
1744 assert_eq!(DrawType::Lines3D, (&feature).into());
1745 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1746 geometry: VectorGeometry::new_multilinestring(
1747 vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]],
1748 None,
1749 ),
1750 ..Default::default()
1751 };
1752 assert_eq!(DrawType::Lines3D, (&feature).into());
1753 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1755 geometry: VectorGeometry::new_polygon(vec![vec![VectorPoint::from_xy(0., 0.)]], None),
1756 ..Default::default()
1757 };
1758 assert_eq!(DrawType::Polygons, (&feature).into());
1759 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1760 geometry: VectorGeometry::new_multipolygon(
1761 vec![vec![vec![VectorPoint::from_xy(0., 0.)]]],
1762 None,
1763 ),
1764 ..Default::default()
1765 };
1766 assert_eq!(DrawType::Polygons, (&feature).into());
1767 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1769 geometry: VectorGeometry::new_polygon(
1770 vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]],
1771 None,
1772 ),
1773 ..Default::default()
1774 };
1775 assert_eq!(DrawType::Polygons3D, (&feature).into());
1776 let feature: VectorFeature<(), Properties, MValue> = VectorFeature {
1777 geometry: VectorGeometry::new_multipolygon(
1778 vec![vec![vec![VectorPoint::from_xyz(0., 0., 1.0)]]],
1779 None,
1780 ),
1781 ..Default::default()
1782 };
1783 assert_eq!(DrawType::Polygons3D, (&feature).into());
1784 }
1785}