use std::collections::HashSet;
use std::convert::TryInto;
use std::hash::Hash;
use serde::Deserialize;
use serde::Serialize;
use crate::codebook::Codebook;
use crate::error::IndexError;
use crate::index::ColumnIndex;
use crate::interface::oracle::utils;
use crate::Datum;
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, PartialOrd, Hash)]
#[serde(rename_all = "snake_case")]
#[derive(Default)]
pub enum Given<Ix: ColumnIndex> {
Conditions(Vec<(Ix, Datum)>),
#[default]
Nothing,
}
impl<Ix: ColumnIndex> Given<Ix> {
pub fn is_nothing(&self) -> bool {
matches!(self, Given::Nothing)
}
pub fn is_conditions(&self) -> bool {
matches!(self, Given::Conditions(..))
}
pub fn canonical(
self,
codebook: &Codebook,
) -> Result<Given<usize>, IndexError> {
match self {
Self::Nothing => Ok(Given::Nothing),
Self::Conditions(mut conditions) => {
let conditions = conditions
.drain(..)
.map(|(col_ix, value)| {
col_ix.col_ix(codebook).and_then(|ix| {
utils::pre_process_datum(value, ix, codebook)
.map(|x| (ix, x))
})
})
.collect::<Result<Vec<(usize, Datum)>, IndexError>>()?;
Ok(Given::Conditions(conditions))
}
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum IntoGivenError {
EmptyConditionsError,
DuplicateConditionIndicesError,
}
impl<Ix: ColumnIndex + Hash + Eq> TryInto<Given<Ix>> for Vec<(Ix, Datum)> {
type Error = IntoGivenError;
fn try_into(mut self) -> Result<Given<Ix>, Self::Error> {
if self.is_empty() {
Ok(Given::Nothing)
} else {
let mut set: HashSet<Ix> = HashSet::new();
if self.drain(..).any(|(ix, _)| !set.insert(ix)) {
Err(IntoGivenError::DuplicateConditionIndicesError)
} else {
Ok(Given::Conditions(self))
}
}
}
}
impl<Ix: ColumnIndex + Hash + Eq> TryInto<Given<Ix>>
for Option<Vec<(Ix, Datum)>>
{
type Error = IntoGivenError;
fn try_into(self) -> Result<Given<Ix>, Self::Error> {
match self {
Some(conditions) => {
if conditions.is_empty() {
Err(IntoGivenError::EmptyConditionsError)
} else {
conditions.try_into()
}
}
None => Ok(Given::Nothing),
}
}
}