bistun-core 2.0.3

The authoritative Linguistic DNA models and DTOs for the Bistun LMS. Provides a high-performance, immutable contract layer for BCP 47 locale resolution, typographic traits, and linguistic metadata.
Documentation
// Copyright (C) 2026 Francis Xavier Wazeter IV
// SPDX-License-Identifier: GPL-3.0-or-later
//
// This file is part of the Bistun Linguistic Metadata Service (LMS).
// See the LICENSE file in the workspace root for full license information.

//! # Traits Dictionary & Enumerations
//! **Crate**: `bistun-core`
//! **Ref**: `[011-LMS-DTO]`
//! **Domain**: `Typology`
//! **Location**: `crates/bistun-core/src/traits.rs`
//!
//! **Why**: This module defines the shared vocabulary (`TraitKey` and Enums) used to encapsulate the `Typology (ISO 639-3)` and `Orthography (ISO 15924)` properties of a locale.
//! **Impact**: If this module is compromised, the `CapabilityManifest (DTO)` cannot be constructed, breaking the capability engine and causing downstream services to fail.
//!
//! ### Architectural Topology
//! * **Tier**: `0`
//! * **Dependencies**: `serde`
//! * **Consumers**: `bistun-lms`, `bistun-cli`
//! * **State Model**: `Stateless`
//! * **Design Patterns**: `Untagged Serialization`
//!
//! ### Local Definitions
//! * **Typology (ISO 639-3)**: The structural classification of languages based on grammar and syntax rules (e.g., Agglutinative vs. Isolating).
//! * **Orthography (ISO 15924)**: The technical rendering mechanics of a writing system, dictating rules like text direction and font shaping.
//! * **Pessimistic Complexity Heuristic**: A conflict-resolution algorithm used in multi-script environments. It always selects the most computationally expensive requirement (e.g., forcing dictionary-based segmentation if even one script requires it).
//! * **Untagged Serialization**: A Serde configuration where enums are serialized as their underlying value rather than explicitly wrapping them in their variant name.

use serde::{Deserialize, Serialize};

/// The "Golden Set" of trait keys used in the `CapabilityManifest (DTO)`.
///
/// **Time**: `O(1)` | **Space**: `O(1)`
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: TraitKey
/// description: The deterministic keys used to map linguistic traits.
/// ```
///
/// # Algorithmic Execution Trace (Internal)
/// 1. Represents standard keys for the `DTO` `traits` map.
/// 2. Utilizes `SCREAMING_SNAKE_CASE` serialization to match the `DTO` standard.
///
/// # Examples
/// ```rust
/// # // The '#' hides this setup boilerplate from docs.rs.
/// # use bistun_core::traits::TraitKey;
/// let key = TraitKey::SegmentationStrategy;
/// assert_eq!(key, TraitKey::SegmentationStrategy);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum TraitKey {
    // --- Rendering & Orthography ---
    /// The primary layout direction (e.g., `LTR`, `RTL`).
    PrimaryDirection,
    /// Indicates if the text naturally contains bidirectional elements.
    HasBidiElements,
    /// Indicates if the script requires complex shaping (e.g., Arabic).
    RequiresShaping,
    /// Unicode blocks to preload for rendering.
    UnicodePreloadBlocks,

    // --- Segmentation & Morphology ---
    /// Strategy used for word and sentence boundary detection.
    SegmentationStrategy,
    /// Typological classification of word formation.
    MorphologyType,
    /// Plural category logic required for the locale.
    PluralCategories,

    // --- Cultural Defaults ---
    /// Default numeric system (e.g., `latn`, `arab`).
    DefaultNumberingSystem,
    /// Default calendar system (e.g., `gregory`, `islamic`).
    DefaultCalendar,
}

/// The UI rendering direction derived from `Orthography (ISO 15924)` mechanics.
///
/// **Time**: `O(1)` | **Space**: `O(1)`
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: Direction
/// description: The primary rendering direction required by a script.
/// ```
///
/// # Algorithmic Execution Trace (Internal)
/// 1. Represents the text layout requirements for a specific script.
/// 2. Utilizes `UPPERCASE` serialization for cross-system compatibility.
///
/// # Examples
/// ```rust
/// # // The '#' hides this setup boilerplate from docs.rs.
/// # use bistun_core::traits::Direction;
/// let dir = Direction::RTL;
/// assert_eq!(dir, Direction::RTL);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum Direction {
    /// Left-to-Right layout.
    LTR,
    /// Right-to-Left layout.
    RTL,
    /// Top-to-Bottom layout.
    TTB,
    /// Native bidirectional layout.
    BIDI,
}

/// The boundary detection logic (Segmentation) required by the script.
///
/// Ordered from the lowest complexity to highest to support the `Pessimistic Complexity Heuristic` strategy.
///
/// **Time**: `O(1)` | **Space**: `O(1)`
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: SegType
/// description: The boundary detection logic and complexity level.
/// ```
///
/// # Algorithmic Execution Trace (Internal)
/// 1. Ordered explicitly to allow `Ord` trait derivation to rank complexity automatically.
/// 2. Permits `TraitAggregator` to resolve conflicts seamlessly.
///
/// # Examples
/// ```rust
/// # // The '#' hides this setup boilerplate from docs.rs.
/// # use bistun_core::traits::SegType;
/// // Demonstrating Pessimistic Complexity Heuristic ordinal comparison
/// assert!(SegType::DICTIONARY > SegType::SPACE);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum SegType {
    /// No segmentation required.
    NONE,
    /// Segmentation based on whitespace.
    SPACE,
    /// Segmentation based on individual characters/syllables.
    CHARACTER,
    /// Dictionary-based complex segmentation.
    DICTIONARY,
}

/// The Typological structure of a language's word formation.
///
/// **Time**: `O(1)` | **Space**: `O(1)`
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: MorphType
/// description: The typological classification of a language's structural grammar.
/// ```
///
/// # Algorithmic Execution Trace (Internal)
/// 1. Maps language identity to execution strategies for `NLP` operations (e.g., stemming).
///
/// # Examples
/// ```rust
/// # // The '#' hides this setup boilerplate from docs.rs.
/// # use bistun_core::traits::MorphType;
/// let morph = MorphType::AGGLUTINATIVE;
/// assert_eq!(morph, MorphType::AGGLUTINATIVE);
/// ```
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MorphType {
    /// Words are invariant (e.g., Chinese).
    ISOLATING,
    /// Words are formed by stringing together discrete morphemes (e.g., Turkish).
    AGGLUTINATIVE,
    /// Morphemes are fused together in complex ways (e.g., Spanish).
    FUSIONAL,
    /// Words are formed using root consonants and vowel templates (e.g., Arabic).
    TEMPLATIC,
    /// Complex multi-morpheme words acting as entire sentences (e.g., Inuktitut).
    POLYSYNTHETIC,
}

// =====================================================================
// V2.0.0 Rule Engine Directives
// =====================================================================

/// Represents the standard algorithmic directives for the `Rule Engine Aggregation` phase.
///
/// Note: this utilizes `Untagged Serialization` and does not actually appear in the `JSON`, only the inner variants appear.
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: LmsRule
/// description: Untagged enum representing operational execution directives.
/// ```
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(untagged)]
pub enum LmsRule {
    /// Transliteration rule directive.
    Trans(TransRule),
    /// Pluralization rule directive.
    Plural(PluralRule),
    /// Casing rule directive.
    Casing(CasingRule),
    /// Normalization rule directive.
    Norm(NormRule),
}

/// Directives for transliteration and phonetic rendering strategies.
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: TransRule
/// description: Phonetic or script transliteration strategies.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum TransRule {
    /// No transliteration required.
    NONE,
    /// Standard romanization transformation.
    ROMANIZATION,
    /// Phonetic spelling transformation.
    PHONETIC,
    /// ICU4X algorithmic transform capability.
    ICU_TRANSFORM,
}

/// Directives for Unicode normalization logic.
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: NormRule
/// description: Unicode standard normalization forms.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NormRule {
    /// Normalization Form C.
    NFC,
    /// Normalization Form D.
    NFD,
    /// Normalization Form KC.
    NFKC,
    /// Normalization Form KD.
    NFKD,
}

/// Directives for morphological plural category mapping.
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: PluralRule
/// description: Typological rules for determining quantity forms.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PluralRule {
    /// Only cardinal numbers are supported.
    CARDINAL_ONLY,
    /// Ordinal and cardinal numbers are supported.
    ORDINAL_SUPPORT,
    /// Multiple plural categories required (few, many, other, etc.).
    MULTIPLE_CATEGORIES,
}

/// Directives for typographic casing mechanics.
///
/// ### `OpenAPI` Schema
/// ```yaml
/// schema: CasingRule
/// description: Specific typographic constraints for character casing.
/// ```
#[allow(non_camel_case_types)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum CasingRule {
    /// Strict case sensitivity.
    CASE_SENSITIVE,
    /// Case-insensitive matching.
    CASE_INSENSITIVE,
    /// Special Unicode casing rules (e.g., Turkish dotless i).
    UNICODE_SPECIAL,
}

#[cfg(test)]
mod tests {
    use super::*;

    /// **What is being proven**: Verifies that `SegType` follows the `Pessimistic Complexity Heuristic` ordering, ensuring complex dictionary models correctly outrank simpler spacing models during structural comparison.
    #[test]
    fn test_seg_type_high_water_mark_ordering() {
        // [Logic Trace Mapping]
        // [STEP 1]: Setup: Instantiate SegType variants via Ord trait checking.
        // [STEP 2]: Execute: Compare using the derived Ord logic.
        // [STEP 3]: Assert: Verify DICTIONARY ranks higher than SPACE, etc.
        assert!(SegType::DICTIONARY > SegType::SPACE);
        assert!(SegType::CHARACTER > SegType::SPACE);
        assert!(SegType::SPACE > SegType::NONE);
    }

    /// **What is being proven**: Proves that the `TraitKey` variants correctly utilize `SCREAMING_SNAKE_CASE` serialization, which is strictly required for accurate `JSON` mapping in downstream `DTO` payloads.
    #[test]
    fn test_trait_key_serialization() {
        // [Logic Trace Mapping]
        // [STEP 1]: Setup: Instantiate TraitKeys.
        // [STEP 2]: Execute: Serialize to JSON strings.
        // [STEP 3]: Assert: Verify SCREAMING_SNAKE_CASE serialization.
        let key_dir = TraitKey::PrimaryDirection;
        let key_num = TraitKey::DefaultNumberingSystem;

        let json_dir = serde_json::to_string(&key_dir).expect("Failed to serialize trait key");
        let json_num = serde_json::to_string(&key_num).expect("Failed to serialize trait key");

        assert_eq!(json_dir, r#""PRIMARY_DIRECTION""#);
        assert_eq!(json_num, r#""DEFAULT_NUMBERING_SYSTEM""#);
    }
}