use std::collections::HashSet;
#[derive(Debug, PartialEq, Eq)]
pub(crate) enum OptionsError {
TooFew { got: usize, min: usize },
TooMany(usize),
Duplicate(String),
}
pub(crate) fn check_options(
raw: Vec<String>,
min: usize,
max: usize,
) -> Result<Vec<String>, OptionsError> {
let options: Vec<String> = raw
.into_iter()
.map(|o| o.trim().to_string())
.filter(|o| !o.is_empty())
.collect();
if options.len() < min {
return Err(OptionsError::TooFew {
got: options.len(),
min,
});
}
if options.len() > max {
return Err(OptionsError::TooMany(options.len()));
}
let mut seen = HashSet::new();
for opt in &options {
if !seen.insert(opt.as_str()) {
return Err(OptionsError::Duplicate(opt.clone()));
}
}
Ok(options)
}
pub(crate) async fn resolve_channel_or_silent<T>(
session_lookup: impl std::future::Future<Output = Option<T>>,
owner_lookup: impl std::future::Future<Output = Option<T>>,
) -> Option<T> {
match session_lookup.await {
Some(id) => Some(id),
None => owner_lookup.await,
}
}
pub(crate) const DISCORD_LABEL_BUDGET: usize = 80;
pub(crate) const SLACK_LABEL_BUDGET: usize = 75;
pub(crate) fn truncate_label(s: &str, budget: usize) -> String {
if s.chars().count() <= budget {
return s.to_string();
}
let mut out = crate::utils::truncate_chars(s, budget.saturating_sub(3)).to_string();
out.push_str("...");
out
}