vyre 0.4.0

GPU compute intermediate representation with a standard operation library
Documentation
// Shared limits and result types for string matching operations.

/// Maximum haystack/input length accepted by search operations: 64 MiB.
pub const MAX_HAYSTACK_LEN: usize = 64 * 1024 * 1024;

/// Maximum single pattern length accepted by search operations: 4 KiB.
pub const MAX_NEEDLE_LEN: usize = 4 * 1024;

/// Maximum number of patterns accepted by multi-pattern operations.
pub const MAX_PATTERN_COUNT: usize = 4096;

/// Sentinel returned by first-match operations when no match exists.
pub const NOT_FOUND: u32 = u32::MAX;

/// Inclusive-exclusive byte match range emitted by scan operations.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Match {
    /// Zero-based pattern id for multi-pattern scanners.
    pub pattern_id: u32,
    /// Inclusive byte offset where the match starts.
    pub start: u32,
    /// Exclusive byte offset where the match ends.
    pub end: u32,
}

/// Error type for bounded string matching kernels.
pub type MatchError = String;

/// Validate haystack and needle sizes against T47 caps.
///
/// # Errors
///
/// Returns an actionable `Fix: ...` error when either input exceeds the
/// documented maximum.
pub fn validate_search_inputs(haystack: &[u8], needle: &[u8]) -> Result<(), MatchError> {
    validate_haystack(haystack)?;
    validate_needle(needle)
}

/// Validate a haystack/input length against the 64 MiB cap.
///
/// # Errors
///
/// Returns an actionable `Fix: ...` error when the input is too large.
pub fn validate_haystack(haystack: &[u8]) -> Result<(), MatchError> {
    if haystack.len() > MAX_HAYSTACK_LEN {
        return Err(format!(
            "Fix: reduce haystack/input length to <= {MAX_HAYSTACK_LEN} bytes, got {}",
            haystack.len()
        ));
    }
    Ok(())
}

/// Validate a needle/pattern length against the 4 KiB cap.
///
/// # Errors
///
/// Returns an actionable `Fix: ...` error when the pattern is too large.
pub fn validate_needle(needle: &[u8]) -> Result<(), MatchError> {
    if needle.len() > MAX_NEEDLE_LEN {
        return Err(format!(
            "Fix: reduce needle/pattern length to <= {MAX_NEEDLE_LEN} bytes, got {}",
            needle.len()
        ));
    }
    Ok(())
}

/// Validate a multi-pattern input set.
///
/// # Errors
///
/// Returns an actionable `Fix: ...` error when the set is too large or any
/// individual pattern exceeds the 4 KiB cap.
pub fn validate_patterns(patterns: &[&[u8]]) -> Result<(), MatchError> {
    if patterns.len() > MAX_PATTERN_COUNT {
        return Err(format!(
            "Fix: reduce pattern count to <= {MAX_PATTERN_COUNT}, got {}",
            patterns.len()
        ));
    }
    for (index, pattern) in patterns.iter().enumerate() {
        if pattern.len() > MAX_NEEDLE_LEN {
            return Err(format!(
                "Fix: reduce pattern {index} length to <= {MAX_NEEDLE_LEN} bytes, got {}",
                pattern.len()
            ));
        }
    }
    Ok(())
}

/// Convert `usize` to `u32` for committed public offsets.
///
/// # Errors
///
/// Returns an actionable `Fix: ...` error if a future limit change allows an
/// offset outside the public `u32` representation.
pub fn to_u32_offset(offset: usize) -> Result<u32, MatchError> {
    u32::try_from(offset)
        .map_err(|_| format!("Fix: reduce input length so offset {offset} fits in U32"))
}