pub type Ratio = u8;
#[derive(Clone)]
pub struct SampleTarget<E> {
sample_max_per_target: Vec<(usize, E)>,
}
impl<T> SampleTarget<T> {
pub fn evenly(targets: &[T]) -> SampleTarget<T>
where
T: Clone + core::fmt::Debug,
{
SampleTarget::with_ratios(
&targets
.iter()
.map(|target| (1, target.clone()))
.collect::<Vec<_>>(),
)
}
pub fn with_ratios(ratios_and_targets: &[(Ratio, T)]) -> SampleTarget<T>
where
T: Clone + core::fmt::Debug,
{
let nonzero_ratios_and_targets = ratios_and_targets
.iter()
.filter(|(ratio, _)| *ratio > 0u8)
.collect::<Vec<_>>();
if nonzero_ratios_and_targets.is_empty() {
panic!(
"Given argument {ratios_and_targets:?} has no target value \
with non-zero ratio."
);
}
let mut sample_max_per_target = Vec::<(usize, T)>::new();
let mut max = 0usize;
for (ratio, target) in nonzero_ratios_and_targets {
max += *ratio as usize;
sample_max_per_target.push((max, target.clone()));
}
SampleTarget {
sample_max_per_target,
}
}
pub fn map<Q>(self, f: impl Fn(T) -> Q) -> SampleTarget<Q> {
SampleTarget {
sample_max_per_target: self
.sample_max_per_target
.into_iter()
.map(|pair| (pair.0, f(pair.1)))
.collect::<Vec<_>>(),
}
}
pub fn sample_domain_max(&self) -> usize {
self.sample_max_per_target
.last()
.expect("at least one target")
.0
}
pub fn target_from_sample(&self, sample: usize) -> Option<&T> {
self.sample_max_per_target
.iter()
.filter(|(max, _)| sample <= *max)
.map(|(_, target)| target)
.next()
}
pub fn target_from_sample_mut(&mut self, sample: usize) -> Option<&mut T> {
self.sample_max_per_target
.iter_mut()
.filter(|(max, _)| sample <= *max)
.map(|(_, target)| target)
.next()
}
}