1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
use crate::tile_matrix_set::TileMatrixSet;
use crate::tms::Tms;
use once_cell::sync::OnceCell;
use std::collections::HashMap;

/// Registry of tile matrix sets
#[derive(Clone)]
pub struct TileMatrixSets {
    // Registry containing Tms is not supported because of Proj:
    // trait `Send` is not implemented for `*mut proj_sys::PJ_AREA`
    coll: HashMap<String, TileMatrixSet>,
}

#[derive(thiserror::Error, Debug)]
pub enum RegistryError {
    #[error("Tile Matrix set not found: `{0}`")]
    TmsNotFound(String),
    #[error("`{0}` is already a registered TMS")]
    TmsAlreadyRegistered(String),
    #[error(transparent)]
    TmsError(#[from] crate::tms::TmsError),
}

impl TileMatrixSets {
    pub fn new() -> Self {
        Self {
            coll: HashMap::new(),
        }
    }

    pub fn get(&self, id: &str) -> Result<&TileMatrixSet, RegistryError> {
        self.coll
            .get(id)
            .ok_or(RegistryError::TmsNotFound(id.to_string()))
    }

    pub fn lookup(&self, id: &str) -> Result<Tms, RegistryError> {
        self.get(id)?.into_tms().map_err(Into::into)
    }

    pub fn list(&self) -> impl Iterator<Item = &String> {
        self.coll.keys().into_iter()
    }

    pub fn register(
        &mut self,
        custom_tms: Vec<TileMatrixSet>,
        overwrite: bool,
    ) -> Result<(), RegistryError> {
        for tms in custom_tms {
            if self.coll.contains_key(&tms.id) {
                if overwrite {
                    self.coll.insert(tms.id.clone(), tms);
                } else {
                    return Err(RegistryError::TmsAlreadyRegistered(tms.id));
                }
            } else {
                self.coll.insert(tms.id.clone(), tms);
            }
        }
        Ok(())
    }
}

/// Global registry of tile matrix sets
pub fn tms() -> &'static TileMatrixSets {
    static TMS: OnceCell<TileMatrixSets> = OnceCell::new();
    &TMS.get_or_init(|| {
        let mut sets = TileMatrixSets::new();
        let tms = vec![
            #[cfg(feature = "projtransform")]
            include_str!("../data/CanadianNAD83_LCC.json"),
            //include_str!("../data/CDB1GlobalGrid.json"), // Error("missing field `coalesc`", line: 19, column: 67)
            #[cfg(feature = "projtransform")]
            include_str!("../data/EuropeanETRS89_LAEAQuad.json"),
            //include_str!("../data/GNOSISGlobalGrid.json"), // Error("missing field `coalesc`", line: 31, column: 66)
            #[cfg(feature = "projtransform")]
            include_str!("../data/UPSAntarcticWGS84Quad.json"),
            #[cfg(feature = "projtransform")]
            include_str!("../data/UPSArcticWGS84Quad.json"),
            #[cfg(feature = "projtransform")]
            include_str!("../data/UTM31WGS84Quad.json"),
            include_str!("../data/WebMercatorQuad.json"),
            include_str!("../data/WGS1984Quad.json"),
            //include_str!("../data/WorldCRS84Quad.json"), // conflicts with WGS1984Quad
            include_str!("../data/WorldMercatorWGS84Quad.json"),
        ]
        .into_iter()
        .map(|data| TileMatrixSet::from_json(&data).unwrap())
        .collect::<Vec<_>>();
        sets.register(tms, false).unwrap();
        // user_tms_dir = os.environ.get("TILEMATRIXSET_DIRECTORY", None)
        // if user_tms_dir:
        //     tms_paths.extend(list(pathlib.Path(user_tms_dir).glob("*.json")))
        sets
    })
}