use crate::error::{Error, Result};
#[cfg(not(feature = "std"))]
use alloc::collections::BTreeMap as HashMap;
#[cfg(not(feature = "std"))]
use alloc::string::String;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct EpsgDefinition {
pub code: u32,
pub name: String,
pub proj_string: String,
pub wkt: Option<String>,
pub crs_type: CrsType,
pub area_of_use: String,
pub unit: String,
pub datum: String,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum CrsType {
Geographic,
Projected,
Geocentric,
Vertical,
Compound,
Engineering,
}
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/generated_epsg.rs"));
pub struct EpsgDatabase {
pub(crate) definitions: HashMap<u32, EpsgDefinition>,
}
impl EpsgDatabase {
pub fn new() -> Self {
let mut db = Self {
definitions: HashMap::new(),
};
db.initialize_builtin_codes();
db
}
pub fn lookup(&self, code: u32) -> Result<&EpsgDefinition> {
self.definitions
.get(&code)
.ok_or_else(|| Error::epsg_not_found(code))
}
pub fn contains(&self, code: u32) -> bool {
self.definitions.contains_key(&code)
}
pub fn codes(&self) -> Vec<u32> {
let mut codes: Vec<u32> = self.definitions.keys().copied().collect();
codes.sort_unstable();
codes
}
pub fn len(&self) -> usize {
self.definitions.len()
}
pub fn is_empty(&self) -> bool {
self.definitions.is_empty()
}
pub fn add_definition(&mut self, definition: EpsgDefinition) {
self.definitions.insert(definition.code, definition);
}
pub fn remove_definition(&mut self, code: u32) -> Option<EpsgDefinition> {
self.definitions.remove(&code)
}
fn initialize_builtin_codes(&mut self) {
super::geographic::register_geographic_crs(self);
super::utm::register_utm_zones(self);
super::projected::register_projected_crs(self);
super::extended::register_extended_crs(self);
#[cfg(feature = "std")]
register_generated_epsg(self);
}
}
impl Default for EpsgDatabase {
fn default() -> Self {
Self::new()
}
}
#[cfg(feature = "proj-db")]
impl EpsgDatabase {
pub fn populate_from_system_proj_db(&mut self) -> crate::error::Result<Option<usize>> {
use crate::epsg::proj_db::ProjDb;
match ProjDb::open_first_available()? {
None => Ok(None),
Some(proj_db) => Ok(Some(super::proj_db::populate_from_proj_db(self, &proj_db)?)),
}
}
}
#[cfg(feature = "std")]
static EPSG_DB: once_cell::sync::Lazy<EpsgDatabase> = once_cell::sync::Lazy::new(EpsgDatabase::new);
#[cfg(feature = "std")]
pub fn lookup_epsg(code: u32) -> Result<&'static EpsgDefinition> {
EPSG_DB.lookup(code)
}
#[cfg(feature = "std")]
pub fn contains_epsg(code: u32) -> bool {
EPSG_DB.contains(code)
}
#[cfg(feature = "std")]
pub fn available_epsg_codes() -> Vec<u32> {
EPSG_DB.codes()
}