pub mod authentication;
pub mod electro_optical;
pub mod projection;
pub mod raster;
pub use projection::Projection;
pub use raster::Raster;
use serde::{Serialize, de::DeserializeOwned};
use stac::{Catalog, Collection, Fields, Item, Result};
pub trait Extension: Serialize + DeserializeOwned {
const IDENTIFIER: &'static str;
const PREFIX: &'static str;
fn identifier_prefix() -> &'static str {
assert!(Self::IDENTIFIER.starts_with("https://stac-extensions.github.io/"));
let index = Self::IDENTIFIER["https://stac-extensions.github.io/".len()..]
.find('/')
.expect("all identifiers should have a first path segment");
&Self::IDENTIFIER[0.."https://stac-extensions.github.io/".len() + index + 1]
}
}
pub trait Extensions: Fields {
fn extensions(&self) -> &Vec<String>;
fn extensions_mut(&mut self) -> &mut Vec<String>;
fn has_extension<E: Extension>(&self) -> bool {
self.extensions()
.iter()
.any(|extension| extension.starts_with(E::identifier_prefix()))
}
fn extension<E: Extension>(&self) -> Result<E> {
self.fields_with_prefix(E::PREFIX)
}
fn add_extension<E: Extension>(&mut self) {
self.extensions_mut().push(E::IDENTIFIER.to_string());
self.extensions_mut().dedup();
}
fn set_extension<E: Extension>(&mut self, extension: E) -> Result<()> {
self.extensions_mut().push(E::IDENTIFIER.to_string());
self.extensions_mut().dedup();
self.remove_fields_with_prefix(E::PREFIX);
self.set_fields_with_prefix(E::PREFIX, extension)
}
fn remove_extension<E: Extension>(&mut self) {
self.remove_fields_with_prefix(E::PREFIX);
self.extensions_mut()
.retain(|extension| !extension.starts_with(E::identifier_prefix()))
}
}
macro_rules! impl_extensions {
($name:ident) => {
impl Extensions for $name {
fn extensions(&self) -> &Vec<String> {
&self.extensions
}
fn extensions_mut(&mut self) -> &mut Vec<String> {
&mut self.extensions
}
}
};
}
impl_extensions!(Item);
impl_extensions!(Catalog);
impl_extensions!(Collection);
#[cfg(test)]
mod tests {
use crate::{Extension, Extensions, Projection, raster::Raster};
use serde_json::json;
use stac::Item;
#[test]
fn identifer_prefix() {
assert_eq!(
Raster::identifier_prefix(),
"https://stac-extensions.github.io/raster/"
);
assert_eq!(
Projection::identifier_prefix(),
"https://stac-extensions.github.io/projection/"
);
}
#[test]
fn remove_extension() {
let mut item = Item::new("an-id");
item.extensions
.push("https://stac-extensions.github.io/projection/v2.0.0/schema.json".to_string());
let _ = item
.properties
.additional_fields
.insert("proj:code".to_string(), json!("EPSG:4326"));
assert!(item.has_extension::<Projection>());
item.remove_extension::<Projection>();
assert!(!item.has_extension::<Projection>());
assert!(item.extensions.is_empty());
assert!(item.properties.additional_fields.is_empty());
}
}