Skip to main content

ic_build/
batch.rs

1//! Shared input-label validation errors for Cargo grouping and artifact batches.
2
3use std::collections::HashMap;
4
5/// Invalid labels, rejected before the operation performs work.
6#[non_exhaustive]
7#[derive(Clone, Debug, Eq, PartialEq)]
8pub enum BatchLabelError {
9    /// An input label was empty.
10    Empty {
11        /// Zero-based position of the empty label.
12        index: usize,
13    },
14    /// Two inputs used the same label.
15    Duplicate {
16        /// Repeated label.
17        label: String,
18        /// Position of the first occurrence.
19        first_index: usize,
20        /// Position of the repeated occurrence.
21        duplicate_index: usize,
22    },
23}
24
25pub(crate) fn validate_labels<'a>(
26    labels: impl IntoIterator<Item = &'a str>,
27) -> Result<(), BatchLabelError> {
28    let mut seen = HashMap::new();
29    for (index, label) in labels.into_iter().enumerate() {
30        if label.is_empty() {
31            return Err(BatchLabelError::Empty { index });
32        }
33        if let Some(first_index) = seen.insert(label, index) {
34            return Err(BatchLabelError::Duplicate {
35                label: label.to_owned(),
36                first_index,
37                duplicate_index: index,
38            });
39        }
40    }
41    Ok(())
42}
43
44impl std::fmt::Display for BatchLabelError {
45    fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match self {
47            Self::Empty { index } => write!(formatter, "label at index {index} is empty"),
48            Self::Duplicate {
49                label,
50                first_index,
51                duplicate_index,
52            } => write!(
53                formatter,
54                "label {label:?} at index {duplicate_index} duplicates index {first_index}"
55            ),
56        }
57    }
58}
59
60impl std::error::Error for BatchLabelError {}