#![allow(missing_docs)]
use crate::types::World;
use std::collections::{BTreeMap, BTreeSet};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OrganEntry {
pub name: String,
pub namespace: String,
}
#[derive(Debug, Clone)]
pub struct WorldRegistry {
world_organs: BTreeMap<World, Vec<OrganEntry>>,
all_organs: Vec<OrganEntry>,
}
impl WorldRegistry {
pub fn new() -> Self {
Self {
world_organs: BTreeMap::new(),
all_organs: Vec::new(),
}
}
pub fn register(&mut self, world: World, entry: OrganEntry) {
let organs = self.world_organs.entry(world).or_default();
if !organs.iter().any(|o| o.namespace == entry.namespace) {
organs.push(entry.clone());
}
if !self.all_organs.iter().any(|o| o.namespace == entry.namespace) {
self.all_organs.push(entry);
}
}
pub fn organs_by_world(&self, world: World) -> &[OrganEntry] {
self.world_organs
.get(&world)
.map(|v| v.as_slice())
.unwrap_or(&[])
}
pub fn organs(&self) -> &[OrganEntry] {
&self.all_organs
}
pub fn active_worlds(&self) -> Vec<&World> {
self.world_organs
.iter()
.filter(|(_, organs)| !organs.is_empty())
.map(|(w, _)| w)
.collect()
}
pub fn vacant_worlds(&self) -> Vec<&World> {
let active: BTreeSet<&World> = self.world_organs.keys().collect();
World::ALL.iter().filter(|w| !active.contains(w)).collect()
}
}
impl Default for WorldRegistry {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn empty_registry() {
let reg = WorldRegistry::new();
assert!(reg.organs().is_empty());
assert!(reg.active_worlds().is_empty());
assert_eq!(reg.vacant_worlds().len(), 6);
}
#[test]
fn register_organ_to_world() {
let mut reg = WorldRegistry::new();
reg.register(
World::WCN,
OrganEntry {
name: "organ-a".into(),
namespace: "organ_a".into(),
},
);
assert_eq!(reg.organs_by_world(World::WCN).len(), 1);
assert_eq!(reg.organs_by_world(World::WCN)[0].name, "organ-a");
assert_eq!(reg.organs_by_world(World::WAI).len(), 0);
}
#[test]
fn deduplicates_by_namespace() {
let mut reg = WorldRegistry::new();
let entry = OrganEntry {
name: "organ-a".into(),
namespace: "organ_a".into(),
};
reg.register(World::WCN, entry.clone());
reg.register(World::WCN, entry);
assert_eq!(reg.organs_by_world(World::WCN).len(), 1);
assert_eq!(reg.organs().len(), 1);
}
#[test]
fn organ_in_multiple_worlds() {
let mut reg = WorldRegistry::new();
let entry = OrganEntry {
name: "organ-a".into(),
namespace: "organ_a".into(),
};
reg.register(World::WCN, entry.clone());
reg.register(World::WAI, entry);
assert_eq!(reg.organs_by_world(World::WCN).len(), 1);
assert_eq!(reg.organs_by_world(World::WAI).len(), 1);
assert_eq!(reg.organs().len(), 1);
}
#[test]
fn active_and_vacant_worlds() {
let mut reg = WorldRegistry::new();
reg.register(
World::WAI,
OrganEntry {
name: "organ-a".into(),
namespace: "organ_a".into(),
},
);
reg.register(
World::WCN,
OrganEntry {
name: "organ-b".into(),
namespace: "organ_b".into(),
},
);
assert_eq!(reg.active_worlds().len(), 2);
assert_eq!(reg.vacant_worlds().len(), 4);
}
#[test]
fn default_is_empty() {
let reg = WorldRegistry::default();
assert!(reg.organs().is_empty());
}
}