riffdb-types 0.1.0

First-party RiffDB runtime crate (riffdb-types)
Documentation
//! Frozen exact text-match semantics (ADR-0131).

use std::error::Error;
use std::fmt;

/// Semantic exact-text profile version.
pub const EXACT_TEXT_PROFILE_VERSION_V1: u16 = 1;
/// Frozen opaque schema identity for canonical `RXTS` provider checkpoints.
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V1: [u8; 32] = [
    0x9b, 0x8a, 0x2f, 0x7e, 0xd9, 0xfd, 0xf1, 0xc5, 0xd9, 0x68, 0x8f, 0xbd, 0x39, 0xad, 0x3d, 0x86,
    0x20, 0x70, 0xa7, 0x17, 0x74, 0xdc, 0x77, 0x4d, 0x0c, 0xe0, 0x0e, 0xdb, 0x69, 0x1a, 0x1e, 0x40,
];
/// Opaque schema identity for activated V2 checkpoints with typed output rows.
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V2: [u8; 32] = [
    0x58, 0xa4, 0x1e, 0x51, 0x2c, 0x04, 0xef, 0x93, 0xe7, 0xc1, 0xfd, 0xb2, 0xbf, 0xfb, 0x2d, 0x44,
    0xbb, 0x54, 0xfc, 0x76, 0xac, 0x61, 0xab, 0x8e, 0x47, 0x93, 0xf1, 0xf0, 0x1d, 0x2b, 0x2f, 0x8a,
];
/// Opaque schema identity for V3 checkpoints with one compiler-bound typed filter.
pub const EXACT_TEXT_PROVIDER_STATE_SCHEMA_HASH_V3: [u8; 32] = [
    0xda, 0x13, 0x39, 0xc5, 0x30, 0x4c, 0x8d, 0x9d, 0x90, 0x58, 0x74, 0x74, 0x1d, 0xf8, 0xd8, 0xa2,
    0x9a, 0xe8, 0xa6, 0x14, 0xbd, 0x11, 0xe5, 0x53, 0xc7, 0xd9, 0xfc, 0xd0, 0x06, 0x8f, 0xcc, 0x4b,
];
/// Opaque schema identity for ADR-0134 indexed predicate/order checkpoints.
pub const EXACT_PREDICATE_PROVIDER_STATE_SCHEMA_HASH_V4: [u8; 32] = [
    0x60, 0xe6, 0x99, 0xf7, 0x7d, 0x47, 0x2b, 0xb0, 0xc1, 0xa7, 0xc7, 0x78, 0x48, 0x8a, 0x6e, 0xf8,
    0x9e, 0xe7, 0x7e, 0x04, 0x83, 0xdc, 0x62, 0x5e, 0x85, 0xdd, 0xc4, 0x0b, 0x88, 0xc2, 0x0a, 0x28,
];
/// Opaque schema identity for ADR-0145 nullable exact-order checkpoints.
pub const EXACT_PREDICATE_PROVIDER_STATE_SCHEMA_HASH_V5: [u8; 32] = [
    0x7e, 0x64, 0x5e, 0x51, 0x89, 0x2e, 0x83, 0xca, 0x4e, 0x05, 0xaa, 0x24, 0xa4, 0x7a, 0xa9, 0x21,
    0xc4, 0xc5, 0x86, 0xbc, 0xb9, 0x9d, 0x2a, 0x7e, 0x0b, 0x4a, 0x0f, 0x13, 0x39, 0x47, 0xc0, 0xa1,
];
/// Maximum indexed UTF-8 value bytes admitted by V1.
pub const MAX_EXACT_TEXT_VALUE_BYTES_V1: usize = 256;
/// Maximum canonical typed output bytes retained for one exact result row.
pub const MAX_EXACT_TEXT_OUTPUT_ROW_BYTES_V1: usize = 64 * 1024;
/// Maximum bound needle bytes admitted by V1.
pub const MAX_EXACT_TEXT_NEEDLE_BYTES_V1: usize = 64;
/// Maximum indexed rows in one policy/partition state.
pub const MAX_EXACT_TEXT_ROWS_PER_PARTITION_V1: usize = 4_096;
/// Maximum distinct nonempty character-boundary substrings generated by one row.
pub const MAX_EXACT_TEXT_TERMS_PER_ROW_V1: usize =
    MAX_EXACT_TEXT_VALUE_BYTES_V1 * (MAX_EXACT_TEXT_VALUE_BYTES_V1 + 1) / 2;

/// Closed exact matching profiles.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum ExactTextProfileV1 {
    /// Compare exact UTF-8 byte sequences.
    BinaryUtf8V1 = 1,
    /// Compare under ADR-0172's frozen `unicode_fold_v1` transform: Unicode
    /// 17.0.0 NFKC followed by full non-Turkic case folding. Values and needles
    /// are folded by the same function, so matching is case- and
    /// compatibility-insensitive while remaining exact and bytewise.
    UnicodeFoldV1 = 2,
}

impl ExactTextProfileV1 {
    /// Decodes a durable profile discriminant.
    #[must_use]
    pub const fn from_discriminant(value: u8) -> Option<Self> {
        match value {
            1 => Some(Self::BinaryUtf8V1),
            2 => Some(Self::UnicodeFoldV1),
            _ => None,
        }
    }

    /// Applies this profile's transform to matching text.
    ///
    /// A stored value and a submitted needle must both pass through here, or
    /// matching is not symmetric.
    #[must_use]
    pub fn matched_form(self, value: &str) -> String {
        match self {
            Self::BinaryUtf8V1 => value.to_owned(),
            Self::UnicodeFoldV1 => crate::unicode_fold_v1(value),
        }
    }
}

/// Closed exact operators; no wildcard, regex, token, fuzzy, or score shape exists.
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum ExactTextOperatorV1 {
    /// Complete byte equality.
    Equals = 1,
    /// Needle is an exact leading byte sequence.
    StartsWith = 2,
    /// Needle is an exact trailing byte sequence.
    EndsWith = 3,
    /// Needle is an exact contiguous byte sequence.
    Contains = 4,
}

/// Closed total orders supported by exact binary UTF-8 result sets.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[repr(u8)]
pub enum ExactTextOrderV1 {
    /// Indexed value ascending, then canonical authoritative entity-key bytes ascending.
    ValueAscEntityKey = 1,
    /// Indexed value descending, then canonical authoritative entity-key bytes ascending.
    ValueDescEntityKey = 2,
}

/// Input field state before exact matching.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExactTextFieldValueV1<'a> {
    /// Field is absent from an older/optional record.
    Missing,
    /// Field is explicitly null.
    Null,
    /// Field has a canonical UTF-8 value.
    Value(&'a str),
}

/// Canonically bound nonempty exact-text parameter.
#[derive(Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
pub struct ExactTextNeedleV1(String);

impl ExactTextNeedleV1 {
    /// Exact UTF-8 value, with no normalization or interpretation.
    #[must_use]
    pub fn as_str(&self) -> &str {
        &self.0
    }

    /// Canonical profile/version/length/value binding.
    #[must_use]
    pub fn to_canonical_bytes(&self) -> Vec<u8> {
        let bytes = self.0.as_bytes();
        let mut output = Vec::with_capacity(8 + bytes.len());
        output.extend_from_slice(b"RXTN");
        output.extend_from_slice(&EXACT_TEXT_PROFILE_VERSION_V1.to_be_bytes());
        output.extend_from_slice(&(bytes.len() as u16).to_be_bytes());
        output.extend_from_slice(bytes);
        output
    }
}

impl ExactTextProfileV1 {
    /// Binds one nonempty canonical UTF-8 needle under the fixed V1 maximum.
    pub fn bind_needle(self, value: &str) -> Result<ExactTextNeedleV1, ExactTextBindErrorV1> {
        if value.is_empty() {
            return Err(ExactTextBindErrorV1::EmptyNeedle);
        }
        // ADR-0172: transform BEFORE bounding. A folded needle can be longer
        // than its source, so a caller-supplied value checked pre-fold could
        // expand past the limit the check was meant to enforce.
        let bound = self.matched_form(value);
        if bound.len() > MAX_EXACT_TEXT_NEEDLE_BYTES_V1 {
            return Err(ExactTextBindErrorV1::NeedleTooLong);
        }
        // An empty fold of a nonempty needle would match everything; refuse it
        // as the empty needle it effectively is.
        if bound.is_empty() {
            return Err(ExactTextBindErrorV1::EmptyNeedle);
        }
        Ok(ExactTextNeedleV1(bound))
    }

    /// Evaluates the frozen truth table. Missing and null never match.
    #[must_use]
    pub fn matches(
        self,
        operator: ExactTextOperatorV1,
        value: ExactTextFieldValueV1<'_>,
        needle: &ExactTextNeedleV1,
    ) -> bool {
        let ExactTextFieldValueV1::Value(value) = value else {
            return false;
        };
        match operator {
            ExactTextOperatorV1::Equals => value == needle.as_str(),
            ExactTextOperatorV1::StartsWith => value.starts_with(needle.as_str()),
            ExactTextOperatorV1::EndsWith => value.ends_with(needle.as_str()),
            ExactTextOperatorV1::Contains => value.contains(needle.as_str()),
        }
    }
}

/// Typed exact-text bind failures.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ExactTextBindErrorV1 {
    /// Empty needles are refused rather than matching every row.
    EmptyNeedle,
    /// Needle exceeds the compiler-frozen maximum.
    NeedleTooLong,
}

impl fmt::Display for ExactTextBindErrorV1 {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        formatter.write_str(match self {
            Self::EmptyNeedle => "exact text needle must not be empty",
            Self::NeedleTooLong => "exact text needle exceeds its compiled bound",
        })
    }
}

impl Error for ExactTextBindErrorV1 {}

// Exhaustive non-durable ownership inventories for exact-provider admission.
crate::inspect_owned_capacity_copy_v1!(ExactTextOperatorV1);

crate::inspect_owned_capacity_copy_v1!(ExactTextOrderV1);

// Exhaustive non-durable ownership inventories for retained provider data.
crate::inspect_owned_capacity_copy_v1!(ExactTextProfileV1);