pub(crate) fn parse_indices(
input: &str,
max_len: usize,
) -> std::result::Result<Vec<usize>, String> {
let mut unique = Vec::new();
for token in input.split(',') {
let token = token.trim();
if token.is_empty() {
continue;
}
if let Some((start, end)) = token.split_once('-') {
let start = start
.trim()
.parse::<usize>()
.map_err(|_| "Invalid start of range".to_string())?;
let end = end
.trim()
.parse::<usize>()
.map_err(|_| "Invalid end of range".to_string())?;
if start == 0 || end == 0 || start > end {
return Err(
"Invalid range: indexes are 1-based and must be start <= end".to_string(),
);
}
let (start, end) = (start - 1, end - 1);
if end >= max_len {
return Err(format!(
"Range end {input} is above result count {max_len}",
input = end + 1,
));
}
for index in start..=end {
if unique.contains(&index) {
continue;
}
unique.push(index);
}
continue;
}
let index = token
.parse::<usize>()
.map_err(|_| format!("Invalid index '{token}'"))?;
if index == 0 {
return Err("Indexes are 1-based, use 1 or greater".to_string());
}
let index = index - 1;
if index >= max_len {
return Err(format!(
"Index {} is above result count {}",
index + 1,
max_len
));
}
if !unique.contains(&index) {
unique.push(index);
}
}
if unique.is_empty() {
return Err("No valid indexes provided".to_string());
}
Ok(unique)
}