ic-host-artifacts 0.27.4

Bounded host artifact streams, identities, gzip and Wasm inspection
Documentation
//! Pure ordered label admission for caller-owned batches.

use std::collections::HashMap;

/// Invalid labels, rejected before the operation performs work.
#[non_exhaustive]
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum BatchLabelError {
    /// An input label was empty.
    Empty {
        /// Zero-based position of the empty label.
        index: usize,
    },
    /// Two inputs used the same label.
    Duplicate {
        /// Repeated label.
        label: String,
        /// Position of the first occurrence.
        first_index: usize,
        /// Position of the repeated occurrence.
        duplicate_index: usize,
    },
}

/// Reject empty or repeated labels before a caller starts batch work.
///
/// Labels are compared exactly, without trimming, normalization or case folding.
/// Empty batches are valid. The first invalid entry in input order is returned;
/// duplicate errors retain the original and repeated positions. This function
/// performs no batch work and selects no label or operation policy beyond those
/// structural requirements.
/// The iterator is consumed only through the first invalid entry. Callers must
/// keep iteration free of batch effects and finish admission before starting work.
///
/// # Errors
/// Returns the first empty or duplicate label with its zero-based position.
pub fn validate_labels<'a>(
    labels: impl IntoIterator<Item = &'a str>,
) -> Result<(), BatchLabelError> {
    let mut seen = HashMap::new();
    for (index, label) in labels.into_iter().enumerate() {
        if label.is_empty() {
            return Err(BatchLabelError::Empty { index });
        }
        if let Some(first_index) = seen.insert(label, index) {
            return Err(BatchLabelError::Duplicate {
                label: label.to_owned(),
                first_index,
                duplicate_index: index,
            });
        }
    }
    Ok(())
}

impl std::fmt::Display for BatchLabelError {
    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Self::Empty { index } => write!(formatter, "label at index {index} is empty"),
            Self::Duplicate {
                label,
                first_index,
                duplicate_index,
            } => write!(
                formatter,
                "label {label:?} at index {duplicate_index} duplicates index {first_index}"
            ),
        }
    }
}

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

#[cfg(test)]
mod tests;