use std::sync::Arc;
use crate::resolution::rust::dependency::DependencyActivation;
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
pub(super) enum Predicate {
Always,
Stated(Arc<str>),
All(Arc<[Predicate]>),
Any(Arc<[Predicate]>),
}
#[derive(Clone, Copy)]
enum Operator {
All,
Any,
}
pub(super) fn conjoin(left: &Predicate, right: &Predicate) -> Predicate {
combine(left, right, Operator::All)
}
pub(super) fn disjoin(left: &Predicate, right: &Predicate) -> Predicate {
match (left, right) {
(Predicate::Always, _) | (_, Predicate::Always) => Predicate::Always,
(left, right) => combine(left, right, Operator::Any),
}
}
impl Predicate {
pub(super) fn of(activation: &DependencyActivation) -> Self {
match activation {
DependencyActivation::Always => Self::Always,
DependencyActivation::Conditional(condition) => Self::Stated(Arc::clone(condition)),
}
}
pub(super) fn activation(&self) -> DependencyActivation {
match self {
Self::Always => DependencyActivation::Always,
stated => DependencyActivation::Conditional(stated.text()),
}
}
fn text(&self) -> Arc<str> {
match self {
Self::Always => Arc::from("all()"),
Self::Stated(condition) => Arc::clone(condition),
Self::All(operands) => rendered(Operator::All, operands),
Self::Any(operands) => rendered(Operator::Any, operands),
}
}
}
fn combine(left: &Predicate, right: &Predicate, operator: Operator) -> Predicate {
let mut operands = operands_of(left, operator);
operands.extend(operands_of(right, operator));
operands.sort();
operands.dedup();
reduced(operands, operator)
}
fn reduced(operands: Vec<Predicate>, operator: Operator) -> Predicate {
let mut remaining = operands.into_iter();
match (remaining.next(), remaining.len()) {
(None, _) => Predicate::Always,
(Some(single), 0) => single,
(Some(first), _) => operator.over(std::iter::once(first).chain(remaining).collect()),
}
}
fn operands_of(predicate: &Predicate, operator: Operator) -> Vec<Predicate> {
match (predicate, operator) {
(Predicate::Always, _) => Vec::new(),
(Predicate::All(operands), Operator::All) => operands.to_vec(),
(Predicate::Any(operands), Operator::Any) => operands.to_vec(),
(stated, _) => vec![stated.clone()],
}
}
fn rendered(operator: Operator, operands: &[Predicate]) -> Arc<str> {
let joined = operands
.iter()
.map(|operand| operand.text().to_string())
.collect::<Vec<_>>()
.join(", ");
Arc::from(format!("{}({joined})", operator.token()).as_str())
}
impl Operator {
fn over(self, operands: Vec<Predicate>) -> Predicate {
match self {
Self::All => Predicate::All(Arc::from(operands)),
Self::Any => Predicate::Any(Arc::from(operands)),
}
}
fn token(self) -> &'static str {
match self {
Self::All => "all",
Self::Any => "any",
}
}
}