#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) enum MultiValue<T> {
Same(T),
Differing,
}
impl<T: PartialEq> MultiValue<T> {
pub(crate) fn collect(values: impl Iterator<Item = T>) -> Option<Self> {
let mut values = values;
let first = values.next()?;
for value in values {
if value != first {
return Some(Self::Differing);
}
}
Some(Self::Same(first))
}
pub(crate) fn same(&self) -> Option<&T> {
match self {
Self::Same(value) => Some(value),
Self::Differing => None,
}
}
}
pub(crate) fn shown<T: std::fmt::Display>(value: &Option<MultiValue<T>>) -> String {
match value {
Some(MultiValue::Same(value)) => value.to_string(),
Some(MultiValue::Differing) => "-".to_string(),
None => String::new(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn differing_values_report_differing() {
assert_eq!(
MultiValue::collect([1, 2].into_iter()),
Some(MultiValue::Differing)
);
}
#[test]
fn an_empty_selection_has_no_value() {
assert_eq!(MultiValue::<i32>::collect(std::iter::empty()), None);
}
#[test]
fn differing_values_are_shown_as_a_dash() {
assert_eq!(shown(&Some(MultiValue::Differing::<&str>)), "-");
assert_eq!(shown(&Some(MultiValue::Same("individual"))), "individual");
assert_eq!(shown(&None::<MultiValue<&str>>), "");
}
#[test]
fn identical_values_collapse_to_same() {
assert_eq!(
MultiValue::collect([1, 1, 1].into_iter()),
Some(MultiValue::Same(1))
);
}
}