Lines
90.38 %
Functions
44.44 %
//! Canonical modelling collections for table constraints.
use crate::shared::utils::{
short_table_row_entries, table_operand, table_ordered_entries, table_rows,
};
use conjure_cp::ast::{
AbstractLiteral, Atom, Expression as Expr, Literal, Metadata, Moo, SymbolTable,
use conjure_cp::rule_engine::{
ApplicationError::RuleNotApplicable, ApplicationResult, RuleEffect, register_rule,
fn is_collection(expr: &Expr, set: bool) -> bool {
matches!(
(expr, set),
(Expr::AbstractLiteral(_, AbstractLiteral::Set(_)), true)
| (
Expr::Atomic(
_,
Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Set(_)))
),
true
)
Expr::AbstractLiteral(_, AbstractLiteral::Sequence(_)),
false
Atom::Literal(Literal::AbstractLiteral(AbstractLiteral::Sequence(_)))
}
/// Inputs are sequences; relations are sets of sequence rows or sparse sets of tuple pairs.
#[register_rule("Base", 25000, [Table, NegativeTable, ShortTable])]
fn normalise_table_collections(expr: &Expr, _: &SymbolTable) -> ApplicationResult {
let (meta, inputs, rows, sparse) = match expr {
Expr::Table(meta, inputs, rows) | Expr::NegativeTable(meta, inputs, rows) => {
(meta, inputs, rows, false)
Expr::ShortTable(meta, inputs, rows) => (meta, inputs, rows, true),
_ => return Err(RuleNotApplicable),
let input_value = table_operand(inputs);
let changed_inputs = !is_collection(&input_value, false);
let inputs = if !changed_inputs {
inputs.clone()
} else {
Moo::new(Expr::AbstractLiteral(
Metadata::new(),
AbstractLiteral::Sequence(
table_ordered_entries(&input_value).ok_or(RuleNotApplicable)?,
))
let row_value = table_operand(rows);
let entries = table_rows(&row_value).ok_or(RuleNotApplicable)?;
let mut changed_rows = !is_collection(&row_value, true);
let entries = entries
.into_iter()
.map(|row| {
let value = table_operand(&row);
if is_collection(&value, sparse) {
return Ok(row);
changed_rows = true;
let entries = if sparse {
short_table_row_entries(&value)
table_ordered_entries(&value)
.ok_or(RuleNotApplicable)?;
Ok(Expr::AbstractLiteral(
if sparse {
AbstractLiteral::Set(entries)
AbstractLiteral::Sequence(entries)
},
})
.collect::<Result<Vec<_>, _>>()?;
let new_rows = if changed_rows {
AbstractLiteral::Set(entries),
rows.clone()
if !changed_inputs && !changed_rows {
return Err(RuleNotApplicable);
Ok(RuleEffect::pure(match expr {
Expr::Table(..) => Expr::Table(meta.clone(), inputs, new_rows),
Expr::NegativeTable(..) => Expr::NegativeTable(meta.clone(), inputs, new_rows),
Expr::ShortTable(..) => Expr::ShortTable(meta.clone(), inputs, new_rows),
_ => unreachable!(),
}))