weavatrix-search-vector 0.3.1

Persistent, mutable, bounded vector candidate search for Rust and Weavatrix
Documentation
use std::fmt;

/// Typed build and query failures.
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub enum SearchError {
    /// The supplied [`crate::IndexConfig`] cannot construct a valid index.
    InvalidConfig(&'static str),
    /// A vector or query did not match the configured dimensionality.
    DimensionMismatch {
        /// Required number of components.
        expected: usize,
        /// Observed number of components.
        actual: usize,
        /// Input-vector position, or `None` when validating a query.
        vector: Option<usize>,
    },
    /// A vector or query component was NaN or infinite.
    NonFiniteValue {
        /// Input-vector position, or `None` when validating a query.
        vector: Option<usize>,
        /// Position of the invalid component.
        dimension: usize,
    },
    /// A stored vector or query had zero magnitude.
    ZeroVector {
        /// Input-vector position, or `None` when validating a query.
        vector: Option<usize>,
    },
    /// More than one stored vector used the same caller-provided key.
    DuplicateKey(u64),
    /// More than one vector used the same key and per-key vector identifier.
    DuplicateVectorId { key: u64, vector_id: u64 },
    /// Index sizes or degree arithmetic exceeded supported capacity.
    CapacityOverflow,
    /// A fallible reservation for index or query storage failed.
    AllocationFailed,
    /// A bounded build or query worker panicked.
    WorkerPanic,
    /// A filesystem operation failed while reading or writing an index.
    Storage {
        /// Operation that failed.
        operation: &'static str,
        /// Portable operating-system error category.
        kind: std::io::ErrorKind,
    },
    /// A persisted index failed structural or integrity validation.
    CorruptSnapshot(&'static str),
    /// The snapshot format is newer or older than this crate understands.
    UnsupportedSnapshotVersion(u32),
    /// A requested vector key was not present.
    MissingKey(u64),
    /// An embedding provider rejected an input or failed to produce a vector.
    EmbeddingFailed(String),
    /// A local or remote search shard failed.
    ShardFailed {
        /// Stable zero-based shard position.
        shard: usize,
        /// Provider-specific failure text.
        message: String,
    },
    /// Mutations changed while an optimistic compaction was being built.
    MutationConflict,
}

impl SearchError {
    pub(crate) fn storage(operation: &'static str, error: &std::io::Error) -> Self {
        Self::Storage {
            operation,
            kind: error.kind(),
        }
    }
}

impl fmt::Display for SearchError {
    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::InvalidConfig(message) => write!(formatter, "invalid index config: {message}"),
            Self::DimensionMismatch {
                expected,
                actual,
                vector,
            } => match vector {
                Some(vector) => write!(
                    formatter,
                    "vector {vector} has {actual} dimensions; expected {expected}"
                ),
                None => write!(
                    formatter,
                    "query has {actual} dimensions; expected {expected}"
                ),
            },
            Self::NonFiniteValue { vector, dimension } => match vector {
                Some(vector) => {
                    write!(
                        formatter,
                        "vector {vector} has a non-finite value at dimension {dimension}"
                    )
                }
                None => write!(
                    formatter,
                    "query has a non-finite value at dimension {dimension}"
                ),
            },
            Self::ZeroVector {
                vector: Some(vector),
            } => {
                write!(formatter, "vector {vector} has zero magnitude")
            }
            Self::ZeroVector { vector: None } => formatter.write_str("query has zero magnitude"),
            Self::DuplicateKey(key) => write!(formatter, "duplicate vector key {key}"),
            Self::DuplicateVectorId { key, vector_id } => {
                write!(formatter, "duplicate vector id {vector_id} for key {key}")
            }
            Self::CapacityOverflow => formatter.write_str("index capacity arithmetic overflowed"),
            Self::AllocationFailed => formatter.write_str("index allocation failed"),
            Self::WorkerPanic => formatter.write_str("a bounded vector-search worker panicked"),
            Self::Storage { operation, kind } => {
                write!(
                    formatter,
                    "index storage operation {operation} failed: {kind}"
                )
            }
            Self::CorruptSnapshot(message) => {
                write!(formatter, "corrupt vector-index snapshot: {message}")
            }
            Self::UnsupportedSnapshotVersion(version) => {
                write!(
                    formatter,
                    "unsupported vector-index snapshot version {version}"
                )
            }
            Self::MissingKey(key) => write!(formatter, "vector key {key} was not found"),
            Self::EmbeddingFailed(message) => {
                write!(formatter, "embedding provider failed: {message}")
            }
            Self::ShardFailed { shard, message } => {
                write!(formatter, "vector-search shard {shard} failed: {message}")
            }
            Self::MutationConflict => {
                formatter.write_str("mutable index changed repeatedly during compaction")
            }
        }
    }
}

impl std::error::Error for SearchError {}