soma-som-core 0.1.0

Universal soma(som) structural primitives — Quad / Tree / Ring / Genesis / Fingerprint / TemporalLedger / CrossingRecord
Documentation
// SPDX-License-Identifier: LGPL-3.0-only
#![allow(missing_docs)]

//! World Registry — maps organs to their interrogative worlds.
//!
//! **Spec:** OPUS §1.2 (six worlds — the awareness hierarchy)
//! — ring foundation purity. The `WorldId`
//! enum is the structural primitive; this `WorldRegistry` is the lookup
//! carrier — every ring application maps its units to worlds, this type
//! holds that mapping.
//!
//! Built at startup during organ registration. Each organ declares its
//! constitutive world position via `LexiconProvider::primary_world()`
//! (defined in the [`crate::lexicon`] module).
//! The registry is frozen into the ring engine's structure — runtime
//! access is a reference, not recomputation.
//!
//! ## Ontological foundation
//!
//! Six units × six worlds. Each organ occupies exactly one primary world
//! — this is an architectural fact about the organ's cognitive function,
//! not derived data.

use crate::types::World;
use std::collections::{BTreeMap, BTreeSet};

/// A registered organ's identity within the world registry.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OrganEntry {
    /// Display name of the organ. Application-defined.
    pub name: String,
    /// FU.Data namespace prefix. Application-defined.
    pub namespace: String,
}

/// Maps organs to interrogative worlds.
///
/// Built incrementally during `register_lexicon()` — each organ declares
/// its primary world via `LexiconProvider::primary_world()`. The registry
/// is part of the engine's static structure, not recomputed at query time.
#[derive(Debug, Clone)]
pub struct WorldRegistry {
    /// World → organs that have vocabulary in that world.
    world_organs: BTreeMap<World, Vec<OrganEntry>>,
    /// All registered organs (deduplicated).
    all_organs: Vec<OrganEntry>,
}

impl WorldRegistry {
    /// Create an empty registry.
    pub fn new() -> Self {
        Self {
            world_organs: BTreeMap::new(),
            all_organs: Vec::new(),
        }
    }

    /// Register an organ as contributing to a specific world.
    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);
        }
    }

    /// Organs registered in the given world.
    pub fn organs_by_world(&self, world: World) -> &[OrganEntry] {
        self.world_organs
            .get(&world)
            .map(|v| v.as_slice())
            .unwrap_or(&[])
    }

    /// All registered organs.
    pub fn organs(&self) -> &[OrganEntry] {
        &self.all_organs
    }

    /// Worlds that have at least one registered organ.
    pub fn active_worlds(&self) -> Vec<&World> {
        self.world_organs
            .iter()
            .filter(|(_, organs)| !organs.is_empty())
            .map(|(w, _)| w)
            .collect()
    }

    /// Worlds with no registered organs.
    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()
    }
}

// ── Tests ──────────────────────────────���───────────────────────────────────

// inline: exercises module-private items via super::*
#[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);
        // Only one entry in all_organs despite two world registrations
        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());
    }
}