use super::descriptor::SectorDescriptor;
use super::error::CatalogError;
use super::status::RegulatoryStatus;
struct EmbeddedManifest {
key: &'static str,
json: &'static str,
}
const EMBEDDED: &[EmbeddedManifest] = &[
EmbeddedManifest {
key: "battery",
json: include_str!("../../sectors/battery.json"),
},
EmbeddedManifest {
key: "electronics",
json: include_str!("../../sectors/electronics.json"),
},
EmbeddedManifest {
key: "unsold-goods",
json: include_str!("../../sectors/unsold-goods.json"),
},
EmbeddedManifest {
key: "textile",
json: include_str!("../../sectors/textile.json"),
},
EmbeddedManifest {
key: "steel",
json: include_str!("../../sectors/steel.json"),
},
EmbeddedManifest {
key: "construction",
json: include_str!("../../sectors/construction.json"),
},
EmbeddedManifest {
key: "tyre",
json: include_str!("../../sectors/tyre.json"),
},
EmbeddedManifest {
key: "toy",
json: include_str!("../../sectors/toy.json"),
},
EmbeddedManifest {
key: "aluminium",
json: include_str!("../../sectors/aluminium.json"),
},
EmbeddedManifest {
key: "furniture",
json: include_str!("../../sectors/furniture.json"),
},
EmbeddedManifest {
key: "detergent",
json: include_str!("../../sectors/detergent.json"),
},
];
pub struct SectorCatalog {
entries: Vec<SectorDescriptor>,
}
impl SectorCatalog {
#[must_use]
pub fn new() -> Self {
let entries = EMBEDDED
.iter()
.map(|m| {
let descriptor: SectorDescriptor =
serde_json::from_str(m.json).unwrap_or_else(|e| {
panic!("embedded sector manifest '{}' is invalid: {e}", m.key)
});
assert_eq!(
descriptor.key, m.key,
"manifest key '{}' does not match its file key '{}'",
descriptor.key, m.key
);
descriptor
})
.collect();
Self { entries }
}
#[must_use]
pub fn get(&self, key: &str) -> Option<&SectorDescriptor> {
self.entries.iter().find(|d| d.key == key)
}
#[must_use]
pub fn all(&self) -> &[SectorDescriptor] {
&self.entries
}
#[must_use]
pub fn in_force(&self) -> Vec<&SectorDescriptor> {
self.entries
.iter()
.filter(|d| d.status == RegulatoryStatus::InForce)
.collect()
}
#[must_use]
pub fn provisional(&self) -> Vec<&SectorDescriptor> {
self.entries
.iter()
.filter(|d| d.status == RegulatoryStatus::Provisional)
.collect()
}
#[must_use]
pub fn is_in_force(&self, key: &str) -> bool {
self.get(key)
.is_some_and(|d| d.status.allows_determination())
}
#[must_use]
pub fn retention_years(&self, key: &str) -> Option<u32> {
self.get(key).map(|d| d.retention_years)
}
#[must_use]
pub fn current_schema_version(&self, key: &str) -> Option<&str> {
self.get(key).map(|d| d.current_schema_version.as_str())
}
#[must_use]
pub fn resolve_schema_version(&self, key: &str, stored: Option<&str>) -> Option<String> {
match stored {
Some(v) => Some(v.to_owned()),
None => self.current_schema_version(key).map(ToOwned::to_owned),
}
}
#[must_use]
pub fn keys(&self) -> Vec<&str> {
let mut keys: Vec<&str> = self.entries.iter().map(|d| d.key.as_str()).collect();
keys.sort_unstable();
keys
}
pub fn register(&mut self, descriptor: SectorDescriptor) -> Result<(), CatalogError> {
if self.get(&descriptor.key).is_some() {
return Err(CatalogError::AlreadyExists(descriptor.key));
}
if descriptor
.current_schema_version
.parse::<semver::Version>()
.is_err()
{
return Err(CatalogError::InvalidSchemaVersion {
key: descriptor.key,
version: descriptor.current_schema_version,
});
}
if !descriptor
.schema_versions
.contains(&descriptor.current_schema_version)
{
return Err(CatalogError::CurrentVersionNotListed {
key: descriptor.key,
version: descriptor.current_schema_version,
});
}
self.entries.push(descriptor);
Ok(())
}
#[must_use]
pub fn len(&self) -> usize {
self.entries.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
}
impl Default for SectorCatalog {
fn default() -> Self {
Self::new()
}
}