use std::{borrow::Cow, collections::HashMap, fmt::Display, hash::Hash, marker::PhantomData};
use nom::{
branch::alt,
bytes::complete::tag,
character::complete::char,
combinator::{all_consuming, map},
sequence::{delimited, separated_pair},
IResult, Parser,
};
use serde::{
de::{self, Visitor},
Deserialize, Deserializer, Serialize, Serializer,
};
use crate::{
as_str, deserialize_int_vals,
error::UnrollError,
expression::{
identifier, int, range, sequence, tuple, whitespace_seperated, BoolExp, Exp, ExpList,
IntExp,
},
from_string, serialize_list, Instantiation, IntVal, IntoVar, MetaInfo, Placeholder, SimpleRef,
VarRef,
};
macro_rules! constraints_enum {
($(#[$attr:meta])* $vis:vis $name:ident, $basic:meta, $meta:meta, $args:meta, $slide_list:meta) => {
$(#[$attr])*
$vis enum $name<Identifier = String, Var = VarRef<Identifier>> {
#[cfg($basic)]
AllDifferent(AllDifferent<Identifier, Var>),
#[cfg($basic)]
AllEqual(AllEqual<Identifier, Var>),
#[cfg($basic)]
BinPacking(BinPacking<Identifier, Var>),
#[cfg($basic)]
Cardinality(Cardinality<Identifier, Var>),
#[cfg($basic)]
Channel(Channel<Identifier, Var>),
#[cfg($basic)]
Circuit(Circuit<Identifier, Var>),
#[cfg($basic)]
Clause(Clause<Identifier, Var>),
#[cfg($basic)]
Count(Count<Identifier, Var>),
#[cfg($basic)]
Cumulative(Cumulative<Identifier, Var>),
#[cfg($basic)]
Element(Element<Identifier, Var>),
#[cfg($basic)]
Extension(Extension<Identifier, Var>),
#[cfg($basic)]
Instantiation(Instantiation<Identifier, Var>),
#[cfg($basic)]
Intension(Intension<Identifier, Var>),
#[cfg($basic)]
Knapsack(Knapsack<Identifier, Var>),
#[cfg($basic)]
Lex(Lex<Identifier, Var>),
#[cfg($basic)]
Maximum(Maximum<Identifier, Var>),
#[cfg($basic)]
Mdd(Mdd<Identifier, Var>),
#[cfg($basic)]
Minimum(Minimum<Identifier, Var>),
#[cfg($basic)]
NValues(NValues<Identifier, Var>),
#[cfg($basic)]
NoOverlap(NoOverlap<Identifier, Var>),
#[cfg($basic)]
Ordered(Ordered<Identifier, Var>),
#[cfg($basic)]
Precedence(Precedence<Identifier, Var>),
#[cfg($basic)]
Regular(Regular<Identifier, Var>),
#[cfg($basic)]
Sum(Sum<Identifier, Var>),
#[cfg($meta)]
Group(Group<Identifier, Var>),
#[cfg($meta)]
Block(Block<Identifier, Var>),
#[cfg($meta)]
Slide(Slide<Identifier, Var>),
#[cfg(not($basic))]
Constraint(Constraint<Identifier, Var>),
#[cfg($args)]
Args(ExpList<Var>),
#[cfg($slide_list)]
List(SlideList<Var>),
}
};
}
constraints_enum!(
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(
rename_all = "camelCase",
bound(deserialize = "Identifier: From<String>, Var: IntoVar", serialize = "Identifier: Display, Var: Display")
)]
pub Constraint,
all(),
any(),
any(),
any()
);
constraints_enum!(
#[derive(Clone, Debug, PartialEq, Hash)]
pub MetaConstraint,
any(),
all(),
any(),
any()
);
constraints_enum!(
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(
rename_all = "camelCase",
bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
)
)]
CaptureConstraint,
all(),
all(),
any(),
any()
);
constraints_enum!(
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(
rename_all = "camelCase",
bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
)
)]
TemplateCapture,
all(),
any(),
all(),
any()
);
constraints_enum!(
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(
rename_all = "camelCase",
bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
)
)]
SlideCapture,
all(),
any(),
any(),
all()
);
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct AllDifferent<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_exp_tuples",
serialize_with = "serialize_exp_tuples"
)]
pub matrix: Matrix<Var>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub except: Vec<IntVal>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct AllEqual<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub except: Vec<IntVal>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct BinPacking<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub sizes: Vec<IntExp<Var>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub condition: Option<Condition<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub limits: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub loads: Vec<IntExp<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Block<Identifier = String, Var = VarRef<Identifier>> {
#[serde(
default,
rename = "@class",
skip_serializing_if = "Vec::is_empty",
serialize_with = "serialize_list"
)]
pub class: Vec<Identifier>,
#[serde(default, rename = "$value")]
pub constraints: Vec<MetaConstraint<Identifier, Var>>,
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
}
pub type Matrix<Var> = Vec<Vec<IntExp<Var>>>;
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Cardinality<Identifier = String, Var = VarRef<Identifier>> {
pub info: MetaInfo<Identifier>,
pub list: Vec<IntExp<Var>>,
pub values: Vec<IntExp<Var>>,
pub closed: bool,
pub occurs: Vec<Exp<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Channel<Identifier = String, Var = VarRef<Identifier>> {
pub info: MetaInfo<Identifier>,
pub list: Vec<IntExp<Var>>,
pub inverse_list: Vec<IntExp<Var>>,
pub value: Option<IntExp<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
#[serde(bound(serialize = "Identifier: Display, Var: Display"))]
pub struct Circuit<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
pub list: OffsetList<Var>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<IntExp<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Clause<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "deserialize_literals",
serialize_with = "serialize_list"
)]
pub list: Vec<BoolExp<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Condition<Var> {
pub operator: Operator,
pub operand: Exp<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Count<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub values: Vec<IntExp<Var>>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Cumulative<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub origins: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub lengths: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub heights: Vec<IntExp<Var>>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Element<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(default, skip_serializing_if = "OffsetList::is_empty")]
pub list: OffsetList<Var>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_exp_tuples",
serialize_with = "serialize_exp_tuples"
)]
pub matrix: Matrix<Var>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub index: Vec<IntExp<Var>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub value: Option<IntExp<Var>>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub condition: Option<Condition<Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Extension<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_tuples",
serialize_with = "serialize_int_tuples"
)]
pub supports: Vec<Vec<Option<IntVal>>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_tuples",
serialize_with = "serialize_int_tuples"
)]
pub conflicts: Vec<Vec<Option<IntVal>>>,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Group<Identifier = String, Var = VarRef<Identifier>> {
pub info: MetaInfo<Identifier>,
pub constraints: Vec<Constraint<Identifier, Var>>,
pub args: Vec<Vec<Exp<Var>>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Intension<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(alias = "$text")]
pub function: BoolExp<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Knapsack<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub weights: Vec<IntVal>,
#[serde(
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub profits: Vec<IntVal>,
pub condition: [Condition<Var>; 2],
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Maximum<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Mdd<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "Transition::parse_vec",
serialize_with = "serialize_list"
)]
pub transitions: Vec<Transition<Identifier>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Minimum<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct NValues<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub except: Vec<IntVal>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct NoOverlap<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
default = "bool_true",
skip_serializing_if = "is_true",
rename = "@zeroIgnored"
)]
pub zero_ignored: bool,
#[serde(
deserialize_with = "deserialize_exp_tuples",
serialize_with = "serialize_exp_tuples"
)]
pub origins: Vec<Vec<IntExp<Var>>>,
#[serde(
deserialize_with = "deserialize_exp_tuples",
serialize_with = "serialize_exp_tuples"
)]
pub lengths: Vec<Vec<IntExp<Var>>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(deserialize = " Var: IntoVar", serialize = "Var: Display"))]
pub struct OffsetList<Var> {
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(rename = "@startIndex", default, skip_serializing_if = "is_default")]
pub start_index: IntVal,
}
impl<Var> OffsetList<Var> {
fn is_empty(&self) -> bool {
self.list.is_empty()
}
}
#[derive(Clone, Debug, PartialEq, Hash, Serialize)]
#[serde(rename_all = "camelCase")]
pub enum Operator {
Lt,
Le,
Eq,
Ge,
Gt,
Ne,
In,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Ordered<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub lengths: Vec<IntExp<Var>>,
pub operator: Operator,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Precedence<Identifier = String, Var = VarRef<Identifier>> {
pub info: MetaInfo<Identifier>,
pub list: Vec<IntExp<Var>>,
pub values: Vec<IntVal>,
pub covered: bool,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Regular<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
deserialize_with = "Transition::parse_vec",
serialize_with = "serialize_list"
)]
pub transitions: Vec<Transition<Identifier>>,
#[serde(deserialize_with = "from_string", serialize_with = "as_str")]
pub start: Identifier,
#[serde(
rename = "final",
deserialize_with = "from_string",
serialize_with = "as_str"
)]
pub finish: Identifier,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Lex<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
rename = "list",
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_exp_lists",
serialize_with = "serialize_exp_lists"
)]
pub lists: Matrix<Var>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_exp_tuples",
serialize_with = "serialize_exp_tuples"
)]
pub matrix: Matrix<Var>,
pub operator: Operator,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Slide<Identifier = String, Var = VarRef<Identifier>> {
pub info: MetaInfo<Identifier>,
pub circular: bool,
pub lists: Vec<SlideList<Var>>,
pub constraint: Box<Constraint<Identifier, Var>>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(deserialize = "Var: IntoVar", serialize = "Var: Display"))]
pub struct SlideList<Var> {
#[serde(
rename = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
rename = "@offset",
default = "usize_one",
skip_serializing_if = "is_one"
)]
pub offset: usize,
#[serde(rename = "@collect", default, skip_serializing_if = "Option::is_none")]
pub collect: Option<usize>,
}
#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display, Var: Display"
))]
pub struct Sum<Identifier = String, Var = VarRef<Identifier>> {
#[serde(flatten)]
pub info: MetaInfo<Identifier>,
#[serde(
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
pub list: Vec<IntExp<Var>>,
#[serde(
default,
skip_serializing_if = "Vec::is_empty",
deserialize_with = "deserialize_int_vals",
serialize_with = "serialize_list"
)]
pub coeffs: Vec<IntVal>,
pub condition: Condition<Var>,
}
#[derive(Clone, Debug, PartialEq, Hash)]
pub struct Transition<Identifier> {
pub from: Identifier,
pub val: IntVal,
pub to: Identifier,
}
fn bool_true() -> bool {
true
}
fn deserialize_int_tuples<'de, D: Deserializer<'de>>(
deserializer: D,
) -> Result<Vec<Vec<Option<IntVal>>>, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = Vec<Vec<Option<IntVal>>>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an integer")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, tuples) = all_consuming(sequence(alt((
map(tuple(table_entry), |t| vec![t]),
map(char('*'), |_| vec![vec![None]]),
map(range, |r| r.map(|i| vec![Some(i)]).collect()),
))))
.parse(v)
.map_err(|_| E::custom(format!("invalid integer `{v}'")))?;
Ok(tuples.into_iter().flatten().collect())
}
}
deserializer.deserialize_str(V)
}
fn table_entry(input: &str) -> IResult<&str, Option<IntVal>> {
alt((map(char('*'), |_| None), map(int, Some))).parse(input)
}
fn deserialize_literals<'de, D: Deserializer<'de>, Var: IntoVar>(
deserializer: D,
) -> Result<Vec<BoolExp<Var>>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: IntoVar> Visitor<'_> for V<X> {
type Value = Vec<BoolExp<X>>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a list of literals")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let (_, lits) = all_consuming(whitespace_seperated(alt((
map(
delimited(tag("@not@("), VarRef::parse, char(')')),
|v: VarRef<String>| BoolExp::Not(Box::new(BoolExp::Var(X::into_var(v)))),
),
BoolExp::parse,
))))
.parse(v)
.map_err(|_| E::custom(format!("invalid literals `{v}'")))?;
Ok(lits)
}
}
deserializer.deserialize_str(V::<Var>(PhantomData))
}
fn deserialize_exp_lists<'de, D: Deserializer<'de>, Var: IntoVar>(
deserializer: D,
) -> Result<Matrix<Var>, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Var: IntoVar"))]
struct ListElement<Var> {
#[serde(rename = "$text", deserialize_with = "IntExp::parse_vec")]
list: Vec<IntExp<Var>>,
}
Ok(Vec::<ListElement<Var>>::deserialize(deserializer)?
.into_iter()
.map(|l| l.list)
.collect())
}
fn serialize_exp_lists<S: Serializer, Var: Display>(
lists: &Matrix<Var>,
serializer: S,
) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound(serialize = "Var: Display"))]
struct ListElement<'a, Var> {
#[serde(rename = "$text", serialize_with = "serialize_list")]
list: &'a Vec<IntExp<Var>>,
}
lists
.iter()
.map(|list| ListElement { list })
.collect::<Vec<_>>()
.serialize(serializer)
}
fn deserialize_exp_tuples<'de, D: Deserializer<'de>, Var: IntoVar>(
deserializer: D,
) -> Result<Vec<Vec<IntExp<Var>>>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: IntoVar> Visitor<'_> for V<X> {
type Value = Vec<Vec<IntExp<X>>>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a list of integer expression tuples")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let (_, rows) = all_consuming(sequence(alt((
tuple(IntExp::parse),
map(IntExp::parse, |e| vec![e]),
))))
.parse(v)
.map_err(|_| E::custom(format!("invalid integer expressions `{v}'")))?;
Ok(rows)
}
}
deserializer.deserialize_str(V::<Var>(PhantomData))
}
fn serialize_exp_tuples<S: Serializer, T: Display>(
vals: &[Vec<T>],
serializer: S,
) -> Result<S::Ok, S::Error> {
if vals.iter().all(|t| t.len() == 1) {
return serialize_list(&vals.iter().flatten().collect::<Vec<_>>(), serializer);
}
serializer.serialize_str(
&vals
.iter()
.map(|t| {
format!(
"({})",
t.iter()
.map(|e| e.to_string())
.collect::<Vec<_>>()
.join(",")
)
})
.collect::<Vec<_>>()
.join(""),
)
}
fn is_default<T: Default + PartialEq>(val: &T) -> bool {
val == &T::default()
}
fn is_false(x: &bool) -> bool {
!x
}
fn is_true(x: &bool) -> bool {
*x
}
fn is_one(x: &usize) -> bool {
*x == 1
}
fn usize_one() -> usize {
1
}
fn serialize_int_tuples<S: Serializer>(
vals: &[Vec<Option<IntVal>>],
serializer: S,
) -> Result<S::Ok, S::Error> {
serializer.serialize_str(
&vals
.iter()
.map(|e| {
format!(
"({})",
e.iter()
.map(|e| match e {
Some(e) => e.to_string(),
None => "*".to_owned(),
})
.collect::<Vec<_>>()
.join(",")
)
})
.collect::<Vec<_>>()
.join(""),
)
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Block<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Block<Identifier, Var> {
#[serde(default, rename = "@id", deserialize_with = "crate::deserialize_ident")]
pub identifier: Option<Identifier>,
#[serde(default, rename = "@note")]
pub note: Option<String>,
#[serde(default, rename = "@class")]
pub class: Vec<String>,
#[serde(default, rename = "$value")]
pub constraints: Vec<MetaConstraint<Identifier, Var>>,
}
let c = Block::deserialize(deserializer)?;
let class: Vec<_> = c.class.into_iter().map(Into::into).collect();
Ok(Self {
info: MetaInfo {
identifier: c.identifier,
note: c.note,
},
class,
constraints: c.constraints,
})
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de>
for Cardinality<Identifier, Var>
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Var: IntoVar"))]
struct Values<Var> {
#[serde(default, rename = "@closed")]
closed: Option<bool>,
#[serde(rename = "$text", deserialize_with = "IntExp::parse_vec")]
list: Vec<IntExp<Var>>,
}
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Cardinality<Identifier, Var> {
#[serde(flatten)]
info: MetaInfo<Identifier>,
#[serde(deserialize_with = "IntExp::parse_vec")]
list: Vec<IntExp<Var>>,
values: Values<Var>,
#[serde(deserialize_with = "Exp::parse_vec")]
occurs: Vec<Exp<Var>>,
}
let x = Cardinality::deserialize(deserializer)?;
Ok(Self {
info: x.info,
list: x.list,
values: x.values.list,
closed: x.values.closed.unwrap_or(false),
occurs: x.occurs,
})
}
}
impl<Identifier: Display, Var: Display> Serialize for Cardinality<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound(serialize = "Var: Display"))]
struct Values<'a, Var> {
#[serde(rename = "@closed", skip_serializing_if = "is_false")]
closed: bool,
#[serde(rename = "$text", serialize_with = "serialize_list")]
list: &'a Vec<IntExp<Var>>,
}
#[derive(Serialize)]
#[serde(bound(serialize = "Identifier: Display, Var: Display"))]
struct Cardinality<'a, Identifier, Var> {
#[serde(flatten)]
info: &'a MetaInfo<Identifier>,
#[serde(serialize_with = "serialize_list")]
list: &'a Vec<IntExp<Var>>,
values: Values<'a, Var>,
#[serde(serialize_with = "serialize_list")]
occurs: &'a Vec<Exp<Var>>,
}
let x = Cardinality {
info: &self.info,
list: &self.list,
values: Values {
closed: self.closed,
list: &self.values,
},
occurs: &self.occurs,
};
x.serialize(serializer)
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Channel<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "I: From<String>, V: IntoVar"))]
struct Channel<'a, I, V> {
#[serde(flatten)]
info: MetaInfo<I>,
list: Vec<Cow<'a, str>>,
#[serde(default)]
value: Option<IntExp<V>>,
}
let c = Channel::deserialize(deserializer)?;
if c.list.is_empty() {
return Err(de::Error::missing_field("list"));
}
let (_, list) = all_consuming(whitespace_seperated(IntExp::parse))
.parse(c.list[0].trim())
.map_err(|_| {
de::Error::custom(format!(
"invalid integer expressions `{}'",
c.list[0].trim()
))
})?;
let inverse_list = if let Some(inverse_list) = c.list.get(1) {
let inverse_list = inverse_list.trim();
all_consuming(whitespace_seperated(IntExp::parse))
.parse(inverse_list)
.map_err(|_| {
de::Error::custom(format!("invalid integer expressions `{inverse_list}'"))
})?
.1
} else {
Vec::new()
};
Ok(Self {
info: c.info,
list,
inverse_list,
value: c.value,
})
}
}
impl<Identifier: Display, Var: Display> Serialize for Channel<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound(serialize = "I: Display, V: Display"))]
struct Channel<'a, I, V> {
#[serde(flatten)]
info: &'a MetaInfo<I>,
list: Vec<String>,
#[serde(skip_serializing_if = "Option::is_none")]
value: &'a Option<IntExp<V>>,
}
let p = |i: &Vec<IntExp<Var>>| -> String {
i.iter()
.map(|e| format!("{}", e))
.collect::<Vec<_>>()
.join(" ")
};
let mut c = Channel {
info: &self.info,
list: vec![p(&self.list)],
value: &self.value,
};
if !self.inverse_list.is_empty() {
c.list.push(p(&self.inverse_list))
}
c.serialize(serializer)
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Circuit<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound = "Identifier: From<String>, Var: IntoVar")]
struct Circuit<Identifier, Var> {
#[serde(flatten)]
info: MetaInfo<Identifier>,
#[serde(default, deserialize_with = "IntExp::parse_vec", alias = "$text")]
simple: Vec<IntExp<Var>>,
#[serde(default)]
list: OffsetList<Var>,
#[serde(default)]
size: Option<IntExp<Var>>,
}
let mut x = Circuit::deserialize(deserializer)?;
if !x.simple.is_empty() {
x.list = OffsetList {
list: x.simple,
start_index: 0,
};
}
Ok(Self {
info: x.info,
list: x.list,
size: x.size,
})
}
}
impl<'de, Var: IntoVar> Deserialize<'de> for Condition<Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Condition<Var>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: IntoVar> Visitor<'_> for V<X> {
type Value = Condition<X>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a condition")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let mut parser = delimited(
char('('),
separated_pair(Operator::parse, char(','), Exp::parse),
char(')'),
);
let (_, (operator, operand)) = parser
.parse(v)
.map_err(|e| E::custom(format!("invalid condition {e:?}")))?;
Ok(Condition { operator, operand })
}
}
deserializer.deserialize_str(V(PhantomData::<Var>))
}
}
impl<Identifier: Clone + Hash + Eq + ToString> Condition<VarRef<Identifier>> {
fn unroll(
&self,
arrays: &HashMap<Identifier, &[usize]>,
args: &[Vec<Exp<SimpleRef<Identifier>>>],
remainder: &[Exp<SimpleRef<Identifier>>],
) -> Result<Condition<SimpleRef<Identifier>>, UnrollError> {
Ok(Condition {
operator: self.operator.clone(),
operand: self.operand.unroll_single(arrays, args, remainder)?,
})
}
}
impl<Var: Display> Display for Condition<Var> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({},{})", self.operator, self.operand)
}
}
impl<Var: Display> Serialize for Condition<Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
serializer.serialize_str(&self.to_string())
}
}
impl<Identifier, I> Constraint<Identifier, VarRef<I>> {
fn max_placeholder(&self) -> Option<usize> {
match self {
Constraint::AllDifferent(AllDifferent { list, matrix, .. }) => list
.iter()
.chain(matrix.iter().flatten())
.filter_map(|exp| exp.max_placeholder())
.max(),
Constraint::AllEqual(AllEqual { list, .. })
| Constraint::Extension(Extension { list, .. })
| Constraint::Mdd(Mdd { list, .. })
| Constraint::Regular(Regular { list, .. })
| Constraint::Precedence(Precedence { list, .. }) => {
list.iter().filter_map(|exp| exp.max_placeholder()).max()
}
Constraint::BinPacking(BinPacking {
list,
sizes,
condition,
limits,
loads,
..
}) => list
.iter()
.chain(sizes)
.chain(limits)
.chain(loads)
.filter_map(|exp| exp.max_placeholder())
.chain(condition.as_ref().and_then(|c| c.operand.max_placeholder()))
.max(),
Constraint::Cardinality(Cardinality {
list,
values,
occurs,
..
}) => list
.iter()
.chain(values)
.filter_map(|exp| exp.max_placeholder())
.chain(occurs.iter().filter_map(|exp| exp.max_placeholder()))
.max(),
Constraint::Channel(Channel {
list,
inverse_list,
value,
..
}) => list
.iter()
.chain(inverse_list)
.chain(value)
.filter_map(|exp| exp.max_placeholder())
.max(),
Constraint::Circuit(Circuit {
list: OffsetList { list, .. },
size,
..
}) => list
.iter()
.chain(size)
.filter_map(|exp| exp.max_placeholder())
.max(),
Constraint::Clause(Clause { list, .. }) => {
list.iter().filter_map(|exp| exp.max_placeholder()).max()
}
Constraint::Count(Count {
list,
values,
condition,
..
}) => list
.iter()
.chain(values)
.filter_map(|exp| exp.max_placeholder())
.chain(condition.operand.max_placeholder())
.max(),
Constraint::Cumulative(Cumulative {
origins,
lengths,
heights,
condition,
..
}) => origins
.iter()
.chain(lengths)
.chain(heights)
.filter_map(|exp| exp.max_placeholder())
.chain(condition.operand.max_placeholder())
.max(),
Constraint::Element(Element {
list: OffsetList { list, .. },
matrix,
index,
value,
condition,
..
}) => list
.iter()
.chain(matrix.iter().flatten())
.chain(index)
.chain(value)
.filter_map(|exp| exp.max_placeholder())
.chain(condition.as_ref().and_then(|c| c.operand.max_placeholder()))
.max(),
Constraint::Instantiation(Instantiation { list, .. }) => list
.iter()
.filter_map(|v| {
if let &VarRef::Placeholder(Placeholder::Position(i)) = v {
Some(i)
} else {
None
}
})
.max(),
Constraint::Intension(Intension { function, .. }) => function.max_placeholder(),
Constraint::Knapsack(Knapsack {
list, condition, ..
}) => list
.iter()
.filter_map(|e| e.max_placeholder())
.chain(condition.iter().filter_map(|c| c.operand.max_placeholder()))
.max(),
Constraint::Lex(Lex { lists, matrix, .. }) => lists
.iter()
.chain(matrix)
.flatten()
.filter_map(|e| e.max_placeholder())
.max(),
Constraint::Maximum(Maximum {
list, condition, ..
})
| Constraint::Minimum(Minimum {
list, condition, ..
})
| Constraint::Sum(Sum {
list, condition, ..
})
| Constraint::NValues(NValues {
list, condition, ..
}) => list
.iter()
.filter_map(|e| e.max_placeholder())
.chain(condition.operand.max_placeholder())
.max(),
Constraint::NoOverlap(NoOverlap {
origins, lengths, ..
}) => origins
.iter()
.chain(lengths)
.flatten()
.flat_map(|e| e.max_placeholder())
.max(),
Constraint::Ordered(Ordered { list, lengths, .. }) => list
.iter()
.chain(lengths)
.filter_map(|e| e.max_placeholder())
.max(),
}
}
}
impl<Identifier: Clone + Hash + Eq + ToString> Constraint<Identifier, VarRef<Identifier>> {
pub(crate) fn unroll(
&self,
arrays: &HashMap<Identifier, &[usize]>,
args: &[Vec<Exp<SimpleRef<Identifier>>>],
remainder: &[Exp<SimpleRef<Identifier>>],
) -> Result<Constraint<Identifier, SimpleRef<Identifier>>, UnrollError> {
let instantiate_exps = |list: &[Exp<_>]| {
let mut nlist = Vec::new();
for e in list {
nlist.extend(e.unroll(arrays, args, remainder)?);
}
Ok(nlist)
};
let instantiate_ints = |list: &[IntExp<_>]| {
let mut nlist = Vec::new();
for e in list {
nlist.extend(e.unroll(arrays, args, remainder)?);
}
Ok(nlist)
};
let instantiate_int_rows = |rows: &[Vec<IntExp<_>>]| {
rows.iter()
.map(|row| instantiate_ints(row))
.collect::<Result<Vec<_>, _>>()
};
let instantiate_matrix = |rows: &[Vec<IntExp<_>>]| {
if let [row] = rows {
if let [IntExp::Var(v @ VarRef::ArrayAccess(_, _))] = &row[..] {
return v
.unroll_matrix(arrays, args, remainder)?
.into_iter()
.map(|row| row.into_iter().map(TryInto::try_into).collect())
.collect();
}
}
instantiate_int_rows(rows)
};
let instantiate_vars = |list: &[VarRef<_>]| {
let mut nlist = Vec::new();
for e in list {
nlist.extend(
e.unroll(arrays, args, remainder)?
.into_iter()
.map(|v| v.into_var())
.collect::<Result<Vec<_>, _>>()?,
);
}
Ok(nlist)
};
match self {
Constraint::AllDifferent(AllDifferent {
info,
list,
matrix,
except,
}) => Ok(Constraint::AllDifferent(AllDifferent {
info: info.clone(),
list: instantiate_ints(list)?,
matrix: instantiate_matrix(matrix)?,
except: except.clone(),
})),
Constraint::AllEqual(AllEqual { info, list, except }) => {
Ok(Constraint::AllEqual(AllEqual {
info: info.clone(),
list: instantiate_ints(list)?,
except: except.clone(),
}))
}
Constraint::BinPacking(BinPacking {
info,
list,
sizes,
condition,
limits,
loads,
}) => {
let condition = if let Some(condition) = condition {
Some(condition.unroll(arrays, args, remainder)?)
} else {
None
};
Ok(Constraint::BinPacking(BinPacking {
info: info.clone(),
list: instantiate_ints(list)?,
sizes: instantiate_ints(sizes)?,
condition,
limits: instantiate_ints(limits)?,
loads: instantiate_ints(loads)?,
}))
}
Constraint::Cardinality(Cardinality {
info,
list,
values,
closed,
occurs,
}) => Ok(Constraint::Cardinality(Cardinality {
info: info.clone(),
list: instantiate_ints(list)?,
values: instantiate_ints(values)?,
closed: *closed,
occurs: instantiate_exps(occurs)?,
})),
Constraint::Channel(Channel {
info,
list,
inverse_list,
value,
}) => {
let value = if let Some(value) = value {
Some(value.unroll_single(arrays, args, remainder)?)
} else {
None
};
Ok(Constraint::Channel(Channel {
info: info.clone(),
list: instantiate_ints(list)?,
inverse_list: instantiate_ints(inverse_list)?,
value,
}))
}
Constraint::Circuit(Circuit {
info,
list: OffsetList { list, start_index },
size,
}) => Ok(Constraint::Circuit(Circuit {
info: info.clone(),
list: OffsetList {
list: instantiate_ints(list)?,
start_index: *start_index,
},
size: if let Some(size) = size {
Some(size.unroll_single(arrays, args, remainder)?)
} else {
None
},
})),
Constraint::Clause(Clause { info, list }) => {
let mut nlist = Vec::with_capacity(list.len());
for e in list {
nlist.extend(e.unroll(arrays, args, remainder)?);
}
Ok(Constraint::Clause(Clause {
info: info.clone(),
list: nlist,
}))
}
Constraint::Count(Count {
info,
list,
values,
condition,
}) => Ok(Constraint::Count(Count {
info: info.clone(),
list: instantiate_ints(list)?,
values: instantiate_ints(values)?,
condition: condition.unroll(arrays, args, remainder)?,
})),
Constraint::Cumulative(Cumulative {
info,
origins,
lengths,
heights,
condition,
}) => Ok(Constraint::Cumulative(Cumulative {
info: info.clone(),
origins: instantiate_ints(origins)?,
lengths: instantiate_ints(lengths)?,
heights: instantiate_ints(heights)?,
condition: condition.unroll(arrays, args, remainder)?,
})),
Constraint::Element(Element {
info,
list: OffsetList { list, start_index },
matrix,
index,
value,
condition,
}) => {
let index = instantiate_ints(index)?;
let value = if let Some(value) = value {
Some(value.unroll_single(arrays, args, remainder)?)
} else {
None
};
let condition = if let Some(condition) = condition {
Some(condition.unroll(arrays, args, remainder)?)
} else {
None
};
Ok(Constraint::Element(Element {
info: info.clone(),
list: OffsetList {
list: instantiate_ints(list)?,
start_index: *start_index,
},
matrix: instantiate_matrix(matrix)?,
index,
value,
condition,
}))
}
Constraint::Extension(Extension {
info,
list,
supports,
conflicts,
}) => Ok(Constraint::Extension(Extension {
info: info.clone(),
list: instantiate_ints(list)?,
supports: supports.clone(),
conflicts: conflicts.clone(),
})),
Constraint::Instantiation(Instantiation {
info,
ty,
cost,
list,
values,
}) => Ok(Constraint::Instantiation(Instantiation {
info: info.clone(),
ty: ty.clone(),
cost: *cost,
list: instantiate_vars(list)?,
values: values.clone(),
})),
Constraint::Intension(Intension { info, function }) => {
Ok(Constraint::Intension(Intension {
info: info.clone(),
function: function.unroll_single(arrays, args, remainder)?,
}))
}
Constraint::Knapsack(Knapsack {
info,
list,
weights,
profits,
condition: [c1, c2],
}) => Ok(Constraint::Knapsack(Knapsack {
info: info.clone(),
list: instantiate_ints(list)?,
weights: weights.clone(),
profits: profits.clone(),
condition: [
c1.unroll(arrays, args, remainder)?,
c2.unroll(arrays, args, remainder)?,
],
})),
Constraint::Lex(Lex {
info,
lists,
matrix,
operator,
}) => Ok(Constraint::Lex(Lex {
info: info.clone(),
lists: instantiate_int_rows(lists)?,
matrix: instantiate_matrix(matrix)?,
operator: operator.clone(),
})),
Constraint::Maximum(Maximum {
info,
list,
condition,
}) => Ok(Constraint::Maximum(Maximum {
info: info.clone(),
list: instantiate_ints(list)?,
condition: condition.unroll(arrays, args, remainder)?,
})),
Constraint::Mdd(Mdd {
info,
list,
transitions,
}) => Ok(Constraint::Mdd(Mdd {
info: info.clone(),
list: instantiate_ints(list)?,
transitions: transitions.clone(),
})),
Constraint::Minimum(Minimum {
info,
list,
condition,
}) => Ok(Constraint::Minimum(Minimum {
info: info.clone(),
list: instantiate_ints(list)?,
condition: condition.unroll(arrays, args, remainder)?,
})),
Constraint::NValues(NValues {
info,
list,
except,
condition,
}) => Ok(Constraint::NValues(NValues {
info: info.clone(),
list: instantiate_ints(list)?,
except: except.clone(),
condition: condition.unroll(arrays, args, remainder)?,
})),
Constraint::NoOverlap(NoOverlap {
info,
zero_ignored,
origins,
lengths,
}) => Ok(Constraint::NoOverlap(NoOverlap {
info: info.clone(),
zero_ignored: *zero_ignored,
origins: instantiate_int_rows(origins)?,
lengths: instantiate_int_rows(lengths)?,
})),
Constraint::Ordered(Ordered {
info,
list,
lengths,
operator,
}) => Ok(Constraint::Ordered(Ordered {
info: info.clone(),
list: instantiate_ints(list)?,
lengths: instantiate_ints(lengths)?,
operator: operator.clone(),
})),
Constraint::Precedence(Precedence {
info,
list,
values,
covered,
}) => Ok(Constraint::Precedence(Precedence {
info: info.clone(),
list: instantiate_ints(list)?,
values: values.clone(),
covered: *covered,
})),
Constraint::Regular(Regular {
info,
list,
transitions,
start,
finish,
}) => Ok(Constraint::Regular(Regular {
info: info.clone(),
list: instantiate_ints(list)?,
transitions: transitions.clone(),
start: start.clone(),
finish: finish.clone(),
})),
Constraint::Sum(Sum {
info,
list,
coeffs,
condition,
}) => Ok(Constraint::Sum(Sum {
info: info.clone(),
list: instantiate_ints(list)?,
coeffs: coeffs.clone(),
condition: condition.unroll(arrays, args, remainder)?,
})),
}
}
}
impl<Identifier, Var> TryFrom<TemplateCapture<Identifier, Var>> for Constraint<Identifier, Var> {
type Error = ();
fn try_from(value: TemplateCapture<Identifier, Var>) -> Result<Self, Self::Error> {
match value {
TemplateCapture::AllDifferent(all_different) => {
Ok(Constraint::AllDifferent(all_different))
}
TemplateCapture::AllEqual(all_equal) => Ok(Constraint::AllEqual(all_equal)),
TemplateCapture::BinPacking(bin_packing) => Ok(Constraint::BinPacking(bin_packing)),
TemplateCapture::Cardinality(cardinality) => Ok(Constraint::Cardinality(cardinality)),
TemplateCapture::Channel(channel) => Ok(Constraint::Channel(channel)),
TemplateCapture::Circuit(circuit) => Ok(Constraint::Circuit(circuit)),
TemplateCapture::Clause(clause) => Ok(Constraint::Clause(clause)),
TemplateCapture::Count(count) => Ok(Constraint::Count(count)),
TemplateCapture::Cumulative(cumulative) => Ok(Constraint::Cumulative(cumulative)),
TemplateCapture::Element(element) => Ok(Constraint::Element(element)),
TemplateCapture::Extension(extension) => Ok(Constraint::Extension(extension)),
TemplateCapture::Instantiation(instantiation) => {
Ok(Constraint::Instantiation(instantiation))
}
TemplateCapture::Intension(intension) => Ok(Constraint::Intension(intension)),
TemplateCapture::Knapsack(knapsack) => Ok(Constraint::Knapsack(knapsack)),
TemplateCapture::Lex(lex) => Ok(Constraint::Lex(lex)),
TemplateCapture::Maximum(maximum) => Ok(Constraint::Maximum(maximum)),
TemplateCapture::Mdd(mdd) => Ok(Constraint::Mdd(mdd)),
TemplateCapture::Minimum(minimum) => Ok(Constraint::Minimum(minimum)),
TemplateCapture::NValues(nvalues) => Ok(Constraint::NValues(nvalues)),
TemplateCapture::NoOverlap(no_overlap) => Ok(Constraint::NoOverlap(no_overlap)),
TemplateCapture::Ordered(ordered) => Ok(Constraint::Ordered(ordered)),
TemplateCapture::Precedence(precedence) => Ok(Constraint::Precedence(precedence)),
TemplateCapture::Regular(regular) => Ok(Constraint::Regular(regular)),
TemplateCapture::Sum(sum) => Ok(Constraint::Sum(sum)),
TemplateCapture::Args(_) => Err(()),
}
}
}
impl<Identifier, Var> TryFrom<SlideCapture<Identifier, Var>> for Constraint<Identifier, Var> {
type Error = ();
fn try_from(value: SlideCapture<Identifier, Var>) -> Result<Self, Self::Error> {
match value {
SlideCapture::AllDifferent(all_different) => {
Ok(Constraint::AllDifferent(all_different))
}
SlideCapture::AllEqual(all_equal) => Ok(Constraint::AllEqual(all_equal)),
SlideCapture::BinPacking(bin_packing) => Ok(Constraint::BinPacking(bin_packing)),
SlideCapture::Cardinality(cardinality) => Ok(Constraint::Cardinality(cardinality)),
SlideCapture::Channel(channel) => Ok(Constraint::Channel(channel)),
SlideCapture::Circuit(circuit) => Ok(Constraint::Circuit(circuit)),
SlideCapture::Clause(clause) => Ok(Constraint::Clause(clause)),
SlideCapture::Count(count) => Ok(Constraint::Count(count)),
SlideCapture::Cumulative(cumulative) => Ok(Constraint::Cumulative(cumulative)),
SlideCapture::Element(element) => Ok(Constraint::Element(element)),
SlideCapture::Extension(extension) => Ok(Constraint::Extension(extension)),
SlideCapture::Instantiation(instantiation) => {
Ok(Constraint::Instantiation(instantiation))
}
SlideCapture::Intension(intension) => Ok(Constraint::Intension(intension)),
SlideCapture::Knapsack(knapsack) => Ok(Constraint::Knapsack(knapsack)),
SlideCapture::Lex(lex) => Ok(Constraint::Lex(lex)),
SlideCapture::Maximum(maximum) => Ok(Constraint::Maximum(maximum)),
SlideCapture::Mdd(mdd) => Ok(Constraint::Mdd(mdd)),
SlideCapture::Minimum(minimum) => Ok(Constraint::Minimum(minimum)),
SlideCapture::NValues(nvalues) => Ok(Constraint::NValues(nvalues)),
SlideCapture::NoOverlap(no_overlap) => Ok(Constraint::NoOverlap(no_overlap)),
SlideCapture::Ordered(ordered) => Ok(Constraint::Ordered(ordered)),
SlideCapture::Precedence(precedence) => Ok(Constraint::Precedence(precedence)),
SlideCapture::Regular(regular) => Ok(Constraint::Regular(regular)),
SlideCapture::Sum(sum) => Ok(Constraint::Sum(sum)),
SlideCapture::List(_) => Err(()),
}
}
}
impl<Identifier, I> Group<Identifier, VarRef<I>> {
fn max_placeholder(&self) -> Option<usize> {
self.constraints
.iter()
.filter_map(|c| c.max_placeholder())
.max()
}
}
impl<Identifier: Clone + Hash + Eq + ToString> Group<Identifier, VarRef<Identifier>> {
pub fn unroll(
&self,
arrays: &HashMap<Identifier, &[usize]>,
) -> Result<Vec<Constraint<Identifier, SimpleRef<Identifier>>>, UnrollError> {
if self.args.is_empty() {
return self
.constraints
.iter()
.map(|c| c.unroll(arrays, &[], &[]))
.collect();
}
let rem_start = self.max_placeholder().map(|x| x + 1).unwrap_or(0);
let mut flat = Vec::with_capacity(self.constraints.len() * self.args.len());
for args in &self.args {
let expanded = args
.iter()
.map(|arg| arg.unroll(arrays, &[], &[]))
.collect::<Result<Vec<_>, _>>()?;
let remainder: Vec<_> = expanded[rem_start.min(expanded.len())..]
.iter()
.flatten()
.cloned()
.collect();
for constraint in &self.constraints {
flat.push(constraint.unroll(arrays, &expanded, &remainder)?);
}
}
Ok(flat)
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Group<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Group<Identifier, Var> {
#[serde(
rename = "@id",
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "crate::deserialize_ident",
serialize_with = "serialize_ident"
)]
pub identifier: Option<Identifier>,
#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
pub note: Option<String>,
#[serde(default, rename = "$value")]
constraints: Vec<TemplateCapture<Identifier, Var>>,
}
let grp: Group<Identifier, Var> = Deserialize::deserialize(deserializer)?;
let mut args = Vec::new();
let constraints = grp
.constraints
.into_iter()
.filter_map(|c| match c {
TemplateCapture::Args(x) => {
args.push(x.elements);
None
}
_ => Some(c.try_into().unwrap()),
})
.collect();
Ok(Self {
info: MetaInfo {
identifier: grp.identifier,
note: grp.note,
},
constraints,
args,
})
}
}
impl<Identifier: Display, Var: Display> Serialize for Group<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound(serialize = "Var: Display"))]
struct ExpList<'a, Var> {
#[serde(rename = "$text", serialize_with = "serialize_list")]
pub(crate) elements: &'a Vec<Exp<Var>>,
}
#[derive(Serialize)]
#[serde(bound(serialize = "Var: Display"), rename_all = "camelCase")]
enum ExpListE<'a, Var> {
Args(ExpList<'a, Var>),
}
#[derive(Serialize)]
#[serde(bound(serialize = "Identifier: Display, Var: Display"))]
struct Group<'a, Identifier, Var> {
#[serde(flatten)]
info: &'a MetaInfo<Identifier>,
#[serde(rename = "$value")]
constraints: &'a Vec<Constraint<Identifier, Var>>,
#[serde(rename = "$value")]
args: Vec<ExpListE<'a, Var>>,
}
Group {
info: &self.info,
constraints: &self.constraints,
args: self
.args
.iter()
.map(|v| ExpListE::Args(ExpList { elements: v }))
.collect(),
}
.serialize(serializer)
}
}
impl<Identifier: Clone + Hash + Eq + ToString> Slide<Identifier, VarRef<Identifier>> {
pub fn unroll(
&self,
arrays: &HashMap<Identifier, &[usize]>,
) -> Result<Vec<Constraint<Identifier, SimpleRef<Identifier>>>, UnrollError> {
let arity = self.constraint.max_placeholder().map_or(0, |i| i + 1);
let lists = self
.lists
.iter()
.map(|l| {
let list = l
.list
.iter()
.map(|e| e.unroll(arrays, &[], &[]))
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.flatten()
.map(|e| Exp::Int(Box::new(e)))
.collect::<Vec<_>>();
let collect = l
.collect
.unwrap_or(if self.lists.len() == 1 { arity } else { 1 });
Ok((list, l.offset, collect))
})
.collect::<Result<Vec<_>, UnrollError>>()?;
let iterations = lists
.iter()
.map(|(list, offset, collect)| {
if list.len() < *collect {
0
} else if self.circular {
list.len().div_ceil(*offset)
} else {
(list.len() - collect) / offset + 1
}
})
.min()
.unwrap_or(0);
let mut flat = Vec::with_capacity(iterations);
for i in 0..iterations {
let mut args = Vec::with_capacity(arity);
for (list, offset, collect) in &lists {
args.extend(
(0..*collect).map(|j| vec![list[(i * offset + j) % list.len()].clone()]),
);
}
flat.push(self.constraint.unroll(arrays, &args, &[])?);
}
Ok(flat)
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Slide<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Deserialize)]
#[serde(bound(deserialize = "Identifier: From<String>, Var: IntoVar"))]
struct Slide<Identifier, Var> {
#[serde(rename = "@id", default, deserialize_with = "crate::deserialize_ident")]
identifier: Option<Identifier>,
#[serde(rename = "@note", default)]
note: Option<String>,
#[serde(rename = "@circular", default)]
circular: bool,
#[serde(default, rename = "$value")]
content: Vec<SlideCapture<Identifier, Var>>,
}
let slide: Slide<Identifier, Var> = Deserialize::deserialize(deserializer)?;
let mut lists = Vec::new();
let mut constraint = None;
for c in slide.content {
match c {
SlideCapture::List(l) => lists.push(l),
c => {
constraint = Some(
c.try_into()
.map_err(|_| de::Error::custom("invalid slide constraint template"))?,
)
}
}
}
let Some(constraint) = constraint else {
return Err(de::Error::missing_field("constraint template"));
};
Ok(Self {
info: MetaInfo {
identifier: slide.identifier,
note: slide.note,
},
circular: slide.circular,
lists,
constraint: Box::new(constraint),
})
}
}
impl<Identifier: Display, Var: Display> Serialize for Slide<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(bound(serialize = "Var: Display"), rename_all = "camelCase")]
enum SlideListE<'a, Var> {
List(&'a SlideList<Var>),
}
#[derive(Serialize)]
#[serde(bound(serialize = "Identifier: Display, Var: Display"))]
struct Slide<'a, Identifier, Var> {
#[serde(flatten)]
info: &'a MetaInfo<Identifier>,
#[serde(rename = "@circular", skip_serializing_if = "is_false")]
circular: bool,
#[serde(rename = "$value")]
lists: Vec<SlideListE<'a, Var>>,
#[serde(rename = "$value")]
constraint: &'a Constraint<Identifier, Var>,
}
Slide {
info: &self.info,
circular: self.circular,
lists: self.lists.iter().map(SlideListE::List).collect(),
constraint: &self.constraint,
}
.serialize(serializer)
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de>
for MetaConstraint<Identifier, Var>
{
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let con: CaptureConstraint<Identifier, Var> = Deserialize::deserialize(deserializer)?;
Ok(con.into())
}
}
impl<Identifier, Var> From<CaptureConstraint<Identifier, Var>> for MetaConstraint<Identifier, Var> {
fn from(value: CaptureConstraint<Identifier, Var>) -> Self {
match value {
CaptureConstraint::AllDifferent(all_different) => {
MetaConstraint::Constraint(Constraint::AllDifferent(all_different))
}
CaptureConstraint::AllEqual(all_equal) => {
MetaConstraint::Constraint(Constraint::AllEqual(all_equal))
}
CaptureConstraint::BinPacking(bin_packing) => {
MetaConstraint::Constraint(Constraint::BinPacking(bin_packing))
}
CaptureConstraint::Cardinality(cardinality) => {
MetaConstraint::Constraint(Constraint::Cardinality(cardinality))
}
CaptureConstraint::Channel(channel) => {
MetaConstraint::Constraint(Constraint::Channel(channel))
}
CaptureConstraint::Circuit(circuit) => {
MetaConstraint::Constraint(Constraint::Circuit(circuit))
}
CaptureConstraint::Clause(clause) => {
MetaConstraint::Constraint(Constraint::Clause(clause))
}
CaptureConstraint::Count(count) => MetaConstraint::Constraint(Constraint::Count(count)),
CaptureConstraint::Cumulative(cumulative) => {
MetaConstraint::Constraint(Constraint::Cumulative(cumulative))
}
CaptureConstraint::Element(element) => {
MetaConstraint::Constraint(Constraint::Element(element))
}
CaptureConstraint::Extension(extension) => {
MetaConstraint::Constraint(Constraint::Extension(extension))
}
CaptureConstraint::Instantiation(instantiation) => {
MetaConstraint::Constraint(Constraint::Instantiation(instantiation))
}
CaptureConstraint::Intension(intension) => {
MetaConstraint::Constraint(Constraint::Intension(intension))
}
CaptureConstraint::Knapsack(knapsack) => {
MetaConstraint::Constraint(Constraint::Knapsack(knapsack))
}
CaptureConstraint::Lex(lex) => MetaConstraint::Constraint(Constraint::Lex(lex)),
CaptureConstraint::Maximum(maximum) => {
MetaConstraint::Constraint(Constraint::Maximum(maximum))
}
CaptureConstraint::Mdd(mdd) => MetaConstraint::Constraint(Constraint::Mdd(mdd)),
CaptureConstraint::Minimum(minimum) => {
MetaConstraint::Constraint(Constraint::Minimum(minimum))
}
CaptureConstraint::NValues(nvalues) => {
MetaConstraint::Constraint(Constraint::NValues(nvalues))
}
CaptureConstraint::NoOverlap(no_overlap) => {
MetaConstraint::Constraint(Constraint::NoOverlap(no_overlap))
}
CaptureConstraint::Ordered(ordered) => {
MetaConstraint::Constraint(Constraint::Ordered(ordered))
}
CaptureConstraint::Precedence(precedence) => {
MetaConstraint::Constraint(Constraint::Precedence(precedence))
}
CaptureConstraint::Regular(regular) => {
MetaConstraint::Constraint(Constraint::Regular(regular))
}
CaptureConstraint::Sum(sum) => MetaConstraint::Constraint(Constraint::Sum(sum)),
CaptureConstraint::Group(group) => MetaConstraint::Group(group),
CaptureConstraint::Block(block) => MetaConstraint::Block(block),
CaptureConstraint::Slide(slide) => MetaConstraint::Slide(slide),
}
}
}
impl<Identifier: Display, Var: Display> Serialize for MetaConstraint<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
#[serde(
bound(serialize = "Identifier: Display, Var: Display"),
rename_all = "camelCase"
)]
enum OutputConstraint<'a, Identifier, Var> {
AllDifferent(&'a AllDifferent<Identifier, Var>),
AllEqual(&'a AllEqual<Identifier, Var>),
BinPacking(&'a BinPacking<Identifier, Var>),
Cardinality(&'a Cardinality<Identifier, Var>),
Channel(&'a Channel<Identifier, Var>),
Circuit(&'a Circuit<Identifier, Var>),
Clause(&'a Clause<Identifier, Var>),
Count(&'a Count<Identifier, Var>),
Cumulative(&'a Cumulative<Identifier, Var>),
Element(&'a Element<Identifier, Var>),
Extension(&'a Extension<Identifier, Var>),
Instantiation(&'a Instantiation<Identifier, Var>),
Intension(&'a Intension<Identifier, Var>),
Knapsack(&'a Knapsack<Identifier, Var>),
Lex(&'a Lex<Identifier, Var>),
Maximum(&'a Maximum<Identifier, Var>),
Mdd(&'a Mdd<Identifier, Var>),
Minimum(&'a Minimum<Identifier, Var>),
NValues(&'a NValues<Identifier, Var>),
NoOverlap(&'a NoOverlap<Identifier, Var>),
Ordered(&'a Ordered<Identifier, Var>),
Precedence(&'a Precedence<Identifier, Var>),
Regular(&'a Regular<Identifier, Var>),
Sum(&'a Sum<Identifier, Var>),
Group(&'a Group<Identifier, Var>),
Block(&'a Block<Identifier, Var>),
Slide(&'a Slide<Identifier, Var>),
}
let c = match self {
MetaConstraint::Group(group) => OutputConstraint::Group(group),
MetaConstraint::Block(block) => OutputConstraint::Block(block),
MetaConstraint::Slide(slide) => OutputConstraint::Slide(slide),
MetaConstraint::Constraint(con) => match con {
Constraint::AllDifferent(all_different) => {
OutputConstraint::AllDifferent(all_different)
}
Constraint::AllEqual(all_equal) => OutputConstraint::AllEqual(all_equal),
Constraint::BinPacking(bin_packing) => OutputConstraint::BinPacking(bin_packing),
Constraint::Cardinality(cardinality) => OutputConstraint::Cardinality(cardinality),
Constraint::Channel(channel) => OutputConstraint::Channel(channel),
Constraint::Circuit(circuit) => OutputConstraint::Circuit(circuit),
Constraint::Clause(clause) => OutputConstraint::Clause(clause),
Constraint::Count(count) => OutputConstraint::Count(count),
Constraint::Cumulative(cumulative) => OutputConstraint::Cumulative(cumulative),
Constraint::Element(element) => OutputConstraint::Element(element),
Constraint::Extension(extension) => OutputConstraint::Extension(extension),
Constraint::Instantiation(instantiation) => {
OutputConstraint::Instantiation(instantiation)
}
Constraint::Intension(intension) => OutputConstraint::Intension(intension),
Constraint::Knapsack(knapsack) => OutputConstraint::Knapsack(knapsack),
Constraint::Lex(lex) => OutputConstraint::Lex(lex),
Constraint::Maximum(maximum) => OutputConstraint::Maximum(maximum),
Constraint::Mdd(mdd) => OutputConstraint::Mdd(mdd),
Constraint::Minimum(minimum) => OutputConstraint::Minimum(minimum),
Constraint::NValues(nvalues) => OutputConstraint::NValues(nvalues),
Constraint::NoOverlap(no_overlap) => OutputConstraint::NoOverlap(no_overlap),
Constraint::Ordered(ordered) => OutputConstraint::Ordered(ordered),
Constraint::Precedence(precedence) => OutputConstraint::Precedence(precedence),
Constraint::Regular(regular) => OutputConstraint::Regular(regular),
Constraint::Sum(sum) => OutputConstraint::Sum(sum),
},
};
Serialize::serialize(&c, serializer)
}
}
impl<Var> Default for OffsetList<Var> {
fn default() -> Self {
Self {
list: Vec::new(),
start_index: IntVal::default(),
}
}
}
impl Operator {
fn parse(input: &str) -> IResult<&str, Self> {
map(
alt((
tag("lt"),
tag("le"),
tag("eq"),
tag("ge"),
tag("gt"),
tag("ne"),
tag("in"),
)),
|op| match op {
"lt" => Self::Lt,
"le" => Self::Le,
"eq" => Self::Eq,
"ge" => Self::Ge,
"gt" => Self::Gt,
"ne" => Self::Ne,
"in" => Self::In,
_ => unreachable!(),
},
)
.parse(input)
}
}
impl<'de> Deserialize<'de> for Operator {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Operator, D::Error> {
struct V;
impl Visitor<'_> for V {
type Value = Operator;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("an operator")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
Ok(all_consuming(Operator::parse)
.parse(v)
.map_err(|e| E::custom(format!("invalid condition {e:?}")))?
.1)
}
}
deserializer.deserialize_str(V)
}
}
impl Display for Operator {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
match self {
Operator::Lt => write!(f, "lt"),
Operator::Le => write!(f, "le"),
Operator::Eq => write!(f, "eq"),
Operator::Ge => write!(f, "ge"),
Operator::Gt => write!(f, "gt"),
Operator::Ne => write!(f, "ne"),
Operator::In => write!(f, "in"),
}
}
}
impl<'de, Identifier: From<String>, Var: IntoVar> Deserialize<'de> for Precedence<Identifier, Var> {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
#[derive(Default, Deserialize)]
struct Values {
#[serde(default, rename = "@covered")]
covered: Option<bool>,
#[serde(rename = "$text", deserialize_with = "deserialize_int_vals")]
list: Vec<IntVal>,
}
#[derive(Deserialize)]
#[serde(bound(
deserialize = "Identifier: From<String>, Var: IntoVar",
serialize = "Identifier: Display"
))]
struct Precedence<Identifier, Var> {
#[serde(flatten)]
info: MetaInfo<Identifier>,
#[serde(
alias = "$text",
deserialize_with = "IntExp::parse_vec",
serialize_with = "serialize_list"
)]
list: Vec<IntExp<Var>>,
#[serde(default)]
values: Values,
}
let x = Precedence::deserialize(deserializer)?;
Ok(Self {
info: x.info,
list: x.list,
values: x.values.list,
covered: x.values.covered.unwrap_or(false),
})
}
}
impl<Identifier: Display, Var: Display> Serialize for Precedence<Identifier, Var> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
#[derive(Serialize)]
struct Values<'a> {
#[serde(rename = "@covered", skip_serializing_if = "is_false")]
covered: bool,
#[serde(rename = "$text", serialize_with = "serialize_list")]
list: &'a Vec<IntVal>,
}
impl Values<'_> {
fn skip(&self) -> bool {
!self.covered && self.list.is_empty()
}
}
#[derive(Serialize)]
#[serde(bound(serialize = "Identifier: Display, Var: Display"))]
struct Precedence<'a, Identifier, Var> {
#[serde(flatten)]
info: &'a MetaInfo<Identifier>,
#[serde(alias = "$text", serialize_with = "serialize_list")]
list: &'a Vec<IntExp<Var>>,
#[serde(skip_serializing_if = "Values::skip")]
values: Values<'a>,
}
let x = Precedence {
info: &self.info,
list: &self.list,
values: Values {
covered: self.covered,
list: &self.values,
},
};
x.serialize(serializer)
}
}
impl<Identifier> From<Constraint<Identifier>> for TemplateCapture<Identifier> {
fn from(value: Constraint<Identifier>) -> Self {
match value {
Constraint::AllDifferent(all_different) => TemplateCapture::AllDifferent(all_different),
Constraint::AllEqual(all_equal) => TemplateCapture::AllEqual(all_equal),
Constraint::BinPacking(bin_packing) => TemplateCapture::BinPacking(bin_packing),
Constraint::Cardinality(cardinality) => TemplateCapture::Cardinality(cardinality),
Constraint::Channel(channel) => TemplateCapture::Channel(channel),
Constraint::Circuit(circuit) => TemplateCapture::Circuit(circuit),
Constraint::Clause(clause) => TemplateCapture::Clause(clause),
Constraint::Count(count) => TemplateCapture::Count(count),
Constraint::Cumulative(cumulative) => TemplateCapture::Cumulative(cumulative),
Constraint::Element(element) => TemplateCapture::Element(element),
Constraint::Extension(extension) => TemplateCapture::Extension(extension),
Constraint::Instantiation(instantiation) => {
TemplateCapture::Instantiation(instantiation)
}
Constraint::Intension(intension) => TemplateCapture::Intension(intension),
Constraint::Knapsack(knapsack) => TemplateCapture::Knapsack(knapsack),
Constraint::Lex(lex) => TemplateCapture::Lex(lex),
Constraint::Maximum(maximum) => TemplateCapture::Maximum(maximum),
Constraint::Mdd(mdd) => TemplateCapture::Mdd(mdd),
Constraint::Minimum(minimum) => TemplateCapture::Minimum(minimum),
Constraint::NValues(nvalues) => TemplateCapture::NValues(nvalues),
Constraint::NoOverlap(no_overlap) => TemplateCapture::NoOverlap(no_overlap),
Constraint::Ordered(ordered) => TemplateCapture::Ordered(ordered),
Constraint::Precedence(precedence) => TemplateCapture::Precedence(precedence),
Constraint::Regular(regular) => TemplateCapture::Regular(regular),
Constraint::Sum(sum) => TemplateCapture::Sum(sum),
}
}
}
impl<Identifier: From<String>> Transition<Identifier> {
fn parse_vec<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<Self>, D::Error> {
struct V<X>(PhantomData<X>);
impl<X: From<String>> Visitor<'_> for V<X> {
type Value = Vec<Transition<X>>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a list of transitions")
}
fn visit_str<E: de::Error>(self, v: &str) -> Result<Self::Value, E> {
let v = v.trim();
let transition = map(
(
char('('),
identifier,
char(','),
int,
char(','),
identifier,
char(')'),
),
|(_, from, _, val, _, to, _)| Transition { from, val, to },
);
let (_, v) = all_consuming(sequence(transition))
.parse(v)
.map_err(|_| E::custom(format!("invalid transitions `{v}'")))?;
Ok(v)
}
}
let visitor = V::<Identifier>(PhantomData);
deserializer.deserialize_str(visitor)
}
}
impl<Identifier: Display> Display for Transition<Identifier> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "({},{},{})", self.from, self.val, self.to)
}
}