pub struct Requirement<F, A, V> {
_arg: std::marker::PhantomData<(A, V)>,
finalized: bool,
func: F,
default: V,
possible_values: std::collections::HashSet<V>,
}
impl<
A,
V: Clone + std::cmp::Eq + std::hash::Hash,
F: Fn(&A) -> V,
> Requirement<F, A, V> {
pub fn new(
func: F,
init: &A,
) -> Self {
let default = func(init);
Requirement {
_arg: std::marker::PhantomData,
finalized: false,
func,
default,
possible_values: Default::default(),
}
}
pub fn add_definite_match(&mut self, v: &Option<A>) {
if self.finalized { return }
let Some(v) = v else { return };
self.possible_values.insert((self.func)(v));
self.finalized = true;
}
pub fn add_possible_match(&mut self, v: &Option<A>) {
if self.finalized { return }
let Some(v) = v else { return };
self.possible_values.insert((self.func)(v));
}
pub fn get_definite(&self) -> Option<V> {
match self.possible_values.len() {
0 => Some(self.default.clone()),
1 => {
let v = self.possible_values.iter().next().unwrap();
if self.finalized {
Some(v.clone())
} else {
if *v == self.default {
Some(self.default.clone())
} else {
None
}
}
}
_ => None,
}
}
pub fn get_finalized(&self) -> Option<V> {
if !self.finalized { return None }
if self.possible_values.len() > 1 { return None }
Some(self.possible_values.iter().next()
.unwrap_or(&self.default)
.clone())
}
pub fn is_possible(&self, v: V) -> bool {
(!self.finalized && self.default == v)
|| self.possible_values.contains(&v)
}
pub fn is_relevant(&self, v: &Option<A>) -> bool {
!self.finalized && v.is_some()
}
pub fn reset(&mut self) {
let Self {
_arg,
ref mut finalized,
func: _,
default: _,
ref mut possible_values,
} = *self;
*finalized = false;
possible_values.clear();
}
}
impl<F, A, V: std::fmt::Debug> std::fmt::Debug for Requirement<F, A, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self {
_arg,
default,
finalized,
func: _,
possible_values,
} = self;
f.debug_struct("Requirement")
.field("finalized", &finalized)
.field("default", default)
.field("possible_values", &possible_values)
.finish()
}
}