1#![warn(missing_docs)]
80#![warn(unused_crate_dependencies, unused_extern_crates)]
81#![warn(variant_size_differences)]
82
83use std::{collections::BTreeMap, fmt::Display};
84
85pub use rangelist::RangeList;
86use serde::{Deserialize, Serialize};
87
88use crate::encapsulate::{
89 deserialize_encapsulated_set, deserialize_encapsulated_string, deserialize_set,
90 serialize_encapsulate_set, serialize_encapsulate_string, serialize_set,
91};
92mod encapsulate;
93
94fn is_false(b: &bool) -> bool {
96 !(*b)
97}
98
99#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
109#[serde(untagged)]
110pub enum Annotation<Identifier = String> {
111 Atom(Identifier),
113 Call(AnnotationCall<Identifier>),
115}
116
117impl<Identifier: Display> Display for Annotation<Identifier> {
118 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
119 write!(f, "::")?;
120 match self {
121 Annotation::Atom(a) => write!(f, "{a}"),
122 Annotation::Call(c) => write!(f, "{c}"),
123 }
124 }
125}
126
127#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
129#[serde(untagged)]
130pub enum AnnotationArgument<Identifier = String> {
131 Array(Vec<AnnotationLiteral<Identifier>>),
133 Literal(AnnotationLiteral<Identifier>),
135}
136
137impl<Idenfier: Display> Display for AnnotationArgument<Idenfier> {
138 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
139 match self {
140 AnnotationArgument::Array(arr) => {
141 write!(f, "[")?;
142 let mut first = true;
143 for v in arr {
144 if !first {
145 write!(f, ", ")?
146 }
147 write!(f, "{v}")?;
148 first = false;
149 }
150 write!(f, "]")
151 }
152 AnnotationArgument::Literal(lit) => write!(f, "{lit}"),
153 }
154 }
155}
156
157#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
159#[serde(rename = "annotation_call")]
160pub struct AnnotationCall<Identifier = String> {
161 pub id: Identifier,
163 pub args: Vec<AnnotationArgument<Identifier>>,
165}
166
167impl<Identifier: Display> Display for AnnotationCall<Identifier> {
168 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
169 write!(f, "{}(", self.id)?;
170 let mut first = true;
171 for arg in &self.args {
172 if !first {
173 write!(f, ", ")?
174 }
175 write!(f, "{arg}")?;
176 first = false;
177 }
178 write!(f, ")")
179 }
180}
181
182#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
184#[serde(untagged)]
185pub enum AnnotationLiteral<Identifier = String> {
186 BaseLiteral(Literal<Identifier>),
188 Annotation(Annotation<Identifier>),
190}
191
192impl<Idenfier: Display> Display for AnnotationLiteral<Idenfier> {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 match self {
195 AnnotationLiteral::BaseLiteral(lit) => write!(f, "{lit}"),
196 AnnotationLiteral::Annotation(ann) => write!(f, "{ann}"),
197 }
198 }
199}
200
201#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
203#[serde(untagged)]
204pub enum Argument<Identifier = String> {
205 Array(Vec<Literal<Identifier>>),
207 Literal(Literal<Identifier>),
209}
210
211impl<Identifier: Display> Display for Argument<Identifier> {
212 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
213 match self {
214 Argument::Array(arr) => {
215 write!(f, "[")?;
216 let mut first = true;
217 for v in arr {
218 if !first {
219 write!(f, ", ")?
220 }
221 write!(f, "{v}")?;
222 first = false;
223 }
224 write!(f, "]")
225 }
226 Argument::Literal(lit) => write!(f, "{lit}"),
227 }
228 }
229}
230
231#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
239#[serde(rename = "array")]
240pub struct Array<Identifier = String> {
241 #[serde(rename = "a")]
243 pub contents: Vec<Literal<Identifier>>,
244 #[serde(default, skip_serializing_if = "Vec::is_empty")]
245 pub ann: Vec<Annotation<Identifier>>,
247 #[serde(default, skip_serializing_if = "is_false")]
248 pub defined: bool,
251 #[serde(default, skip_serializing_if = "is_false")]
252 pub introduced: bool,
256}
257
258impl<Identifier: Ord> Array<Identifier> {
259 fn determine_type(&self, fzn: &FlatZinc<Identifier>) -> (&str, bool) {
261 let ty = match self.contents.first().unwrap() {
262 Literal::Int(_) => "int",
263 Literal::Float(_) => "float",
264 Literal::Identifier(ident) => match fzn.variables[ident].ty {
265 Type::Bool => "bool",
266 Type::Int => "int",
267 Type::Float => "float",
268 Type::IntSet => "set of int",
269 },
270 Literal::Bool(_) => "bool",
271 Literal::IntSet(_) => "set of int",
272 Literal::FloatSet(_) => "set of float",
273 Literal::String(_) => "string",
274 };
275 let is_var = self.contents.iter().any(|lit| match lit {
276 Literal::Identifier(ident) => fzn.variables[ident].value.is_none(),
277 _ => false,
278 });
279 (ty, is_var)
280 }
281}
282
283#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
285#[serde(rename = "constraint")]
286pub struct Constraint<Identifier = String> {
287 pub id: Identifier,
289 pub args: Vec<Argument<Identifier>>,
291 #[serde(default, skip_serializing_if = "Option::is_none")]
293 pub defines: Option<Identifier>,
294 #[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
296 pub ann: Vec<Annotation<Identifier>>,
297}
298
299impl<Identifier: Display> Display for Constraint<Identifier> {
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 write!(f, "{}(", self.id)?;
302 let mut first = true;
303 for arg in &self.args {
304 if !first {
305 write!(f, ", ")?
306 }
307 write!(f, "{arg}")?;
308 first = false;
309 }
310 write!(f, ")")?;
311 if let Some(defines) = &self.defines {
312 write!(f, " ::defines_var({defines})")?
313 }
314 for a in &self.ann {
315 write!(f, " {a}")?
316 }
317 Ok(())
318 }
319}
320
321#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
325#[serde(untagged)]
326pub enum Domain {
327 #[serde(deserialize_with = "deserialize_set", serialize_with = "serialize_set")]
329 Int(RangeList<i64>),
330 #[serde(deserialize_with = "deserialize_set", serialize_with = "serialize_set")]
332 Float(RangeList<f64>),
333}
334
335impl Display for Domain {
336 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
337 match self {
338 Domain::Int(is) => write!(f, "{is}"),
339 Domain::Float(fs) => write!(f, "{fs}"),
340 }
341 }
342}
343
344#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
350pub struct FlatZinc<Identifier: Ord = String> {
351 #[serde(default)]
353 pub variables: BTreeMap<Identifier, Variable<Identifier>>,
354 #[serde(default)]
356 pub arrays: BTreeMap<Identifier, Array<Identifier>>,
357 #[serde(default)]
359 pub constraints: Vec<Constraint<Identifier>>,
360 #[serde(default)]
362 pub output: Vec<Identifier>,
363 pub solve: SolveObjective<Identifier>,
365 #[serde(default, skip_serializing_if = "String::is_empty")]
367 pub version: String,
368}
369
370impl<Identifier: Ord> Default for FlatZinc<Identifier> {
371 fn default() -> Self {
372 Self {
373 variables: Default::default(),
374 arrays: BTreeMap::new(),
375 constraints: Vec::new(),
376 output: Default::default(),
377 solve: Default::default(),
378 version: "1.0".into(),
379 }
380 }
381}
382
383impl<Identifier: Ord + Display> Display for FlatZinc<Identifier> {
384 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
385 let output_map: BTreeMap<&Identifier, ()> =
386 self.output.iter().map(|ident| (ident, ())).collect();
387
388 for (ident, var) in &self.variables {
389 write!(f, "var ")?;
390 if let Some(dom) = &var.domain {
391 write!(f, "{dom}")?
392 } else {
393 write!(f, "{}", var.ty)?
394 }
395 write!(f, ": {ident}")?;
396 if output_map.contains_key(&ident) {
397 write!(f, " ::output_var")?;
398 }
399 if var.defined {
400 write!(f, " ::is_defined_var")?;
401 }
402 if var.introduced {
403 write!(f, " ::var_is_introduced")?;
404 }
405 for ann in &var.ann {
406 write!(f, " {ann}")?
407 }
408 if let Some(val) = &var.value {
409 write!(f, " = {val}")?
410 }
411 writeln!(f, ";")?
412 }
413 for (ident, arr) in &self.arrays {
414 let (ty, is_var) = arr.determine_type(self);
415 write!(
416 f,
417 "array[1..{}] of {}{ty}: {ident}",
418 arr.contents.len(),
419 if is_var { "var " } else { "" }
420 )?;
421 if output_map.contains_key(&ident) {
422 write!(f, " ::output_array([1..{}])", arr.contents.len())?;
423 }
424 if arr.defined {
425 write!(f, " ::is_defined_var")?;
426 }
427 if arr.introduced {
428 write!(f, " ::var_is_introduced")?;
429 }
430 for ann in &arr.ann {
431 write!(f, " {ann}")?
432 }
433 write!(f, " = [")?;
434 let mut first = true;
435 for v in &arr.contents {
436 if !first {
437 write!(f, ", ")?;
438 }
439 write!(f, "{v}")?;
440 first = false;
441 }
442 writeln!(f, "];")?
443 }
444 for c in &self.constraints {
445 writeln!(f, "constraint {c};")?;
446 }
447 writeln!(f, "{};", self.solve)
448 }
449}
450
451#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
456#[serde(untagged)]
457pub enum Literal<Identifier = String> {
458 Int(i64),
460 Float(f64),
462 Identifier(Identifier),
464 Bool(bool),
466 #[serde(
467 serialize_with = "serialize_encapsulate_set",
468 deserialize_with = "deserialize_encapsulated_set"
469 )]
470 IntSet(RangeList<i64>),
472 #[serde(
473 serialize_with = "serialize_encapsulate_set",
474 deserialize_with = "deserialize_encapsulated_set"
475 )]
476 FloatSet(RangeList<f64>),
479 #[serde(
480 serialize_with = "serialize_encapsulate_string",
481 deserialize_with = "deserialize_encapsulated_string"
482 )]
483 String(String),
485}
486
487impl<Identifier: Display> Display for Literal<Identifier> {
488 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
489 match self {
490 Literal::Int(i) => write!(f, "{i}"),
491 Literal::Float(x) => write!(f, "{x:?}"),
492 Literal::Identifier(ident) => write!(f, "{ident}"),
493 Literal::Bool(b) => write!(f, "{b}"),
494 Literal::IntSet(is) => write!(f, "{is}"),
495 Literal::FloatSet(fs) => write!(f, "{fs}"),
496 Literal::String(s) => write!(f, "{s:?}"),
497 }
498 }
499}
500
501#[derive(Default, Clone, PartialEq, Debug, Deserialize, Serialize)]
503#[serde(rename = "method")]
504pub enum Method {
505 #[serde(rename = "satisfy")]
507 #[default]
508 Satisfy,
509 #[serde(rename = "minimize")]
511 Minimize,
512 #[serde(rename = "maximize")]
514 Maximize,
515}
516
517impl Display for Method {
518 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
519 match self {
520 Method::Satisfy => write!(f, "satisfy"),
521 Method::Minimize => write!(f, "minimize"),
522 Method::Maximize => write!(f, "maximize"),
523 }
524 }
525}
526
527#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
529pub struct SolveObjective<Identifier = String> {
530 pub method: Method,
532 #[serde(skip_serializing_if = "Option::is_none")]
534 pub objective: Option<Literal<Identifier>>,
535 #[serde(default, skip_serializing_if = "Vec::is_empty")]
540 pub ann: Vec<Annotation<Identifier>>,
541}
542
543impl<Identifier> Default for SolveObjective<Identifier> {
544 fn default() -> Self {
545 Self {
546 method: Default::default(),
547 objective: None,
548 ann: Vec::new(),
549 }
550 }
551}
552
553impl<Identifier: Display> Display for SolveObjective<Identifier> {
554 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
555 write!(f, "solve ")?;
556 for a in &self.ann {
557 write!(f, "{a} ")?;
558 }
559 write!(f, "{}", self.method)?;
560 if let Some(obj) = &self.objective {
561 write!(f, " {obj}")?
562 }
563 Ok(())
564 }
565}
566
567#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
569#[serde(rename = "type")]
570pub enum Type {
571 #[serde(rename = "bool")]
573 Bool,
574 #[serde(rename = "int")]
576 Int,
577 #[serde(rename = "float")]
579 Float,
580 #[serde(rename = "set of int")]
582 IntSet,
583}
584
585impl Display for Type {
586 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
587 match self {
588 Type::Bool => write!(f, "bool"),
589 Type::Int => write!(f, "int"),
590 Type::Float => write!(f, "float"),
591 Type::IntSet => write!(f, "set of int"),
592 }
593 }
594}
595
596#[derive(Clone, PartialEq, Debug, Deserialize, Serialize)]
598#[serde(rename = "variable")]
599pub struct Variable<Identifier = String> {
600 #[serde(rename = "type")]
602 pub ty: Type,
603 #[serde(skip_serializing_if = "Option::is_none")]
609 pub domain: Option<Domain>,
610 #[serde(rename = "rhs", skip_serializing_if = "Option::is_none")]
613 pub value: Option<Literal<Identifier>>,
614 #[serde(default, skip_serializing_if = "Vec::is_empty")]
616 pub ann: Vec<Annotation<Identifier>>,
617 #[serde(default, skip_serializing_if = "is_false")]
620 pub defined: bool,
621 #[serde(default, skip_serializing_if = "is_false")]
625 pub introduced: bool,
626}
627
628#[cfg(test)]
629mod tests {
630 use std::{
631 collections::BTreeMap,
632 fs::File,
633 io::{BufReader, Read},
634 path::Path,
635 };
636
637 use expect_test::ExpectFile;
638 use ustr::Ustr;
639
640 use crate::{
641 Annotation, AnnotationArgument, AnnotationCall, AnnotationLiteral, Array, Domain, FlatZinc,
642 Literal, Method, RangeList, SolveObjective, Type, Variable,
643 };
644
645 test_file!(documentation_example);
646 test_file!(encapsulated_string);
647 test_file!(float_sets);
648 test_file!(set_literals);
649 test_file!(unit_test_example);
650
651 fn test_successful_serialization(file: &Path, exp: ExpectFile) {
652 let rdr = BufReader::new(File::open(file).unwrap());
653 let fzn: FlatZinc = serde_json::from_reader(rdr).unwrap();
654 exp.assert_debug_eq(&fzn);
655 let fzn2: FlatZinc = serde_json::from_str(&serde_json::to_string(&fzn).unwrap()).unwrap();
656 assert_eq!(fzn, fzn2)
657 }
658
659 macro_rules! test_file {
660 ($file: ident) => {
661 #[test]
662 fn $file() {
663 test_successful_serialization(
664 std::path::Path::new(&format!("./corpus/{}.fzn.json", stringify!($file))),
665 expect_test::expect_file![&format!(
666 "../corpus/{}.debug.txt",
667 stringify!($file)
668 )],
669 )
670 }
671 };
672 }
673 pub(crate) use test_file;
674
675 #[test]
676 fn test_ident_no_copy() {
677 let mut rdr = BufReader::new(
678 File::open(Path::new("./corpus/documentation_example.fzn.json")).unwrap(),
679 );
680 let mut content = String::new();
681 let _ = rdr.read_to_string(&mut content).unwrap();
682
683 let fzn: FlatZinc<&str> = serde_json::from_str(&content).unwrap();
684 expect_test::expect_file!["../corpus/documentation_example.debug.txt"].assert_debug_eq(&fzn)
685 }
686
687 #[test]
688 fn test_ident_interned() {
689 let rdr = BufReader::new(
690 File::open(Path::new("./corpus/documentation_example.fzn.json")).unwrap(),
691 );
692 let fzn: FlatZinc<Ustr> = serde_json::from_reader(rdr).unwrap();
693 expect_test::expect_file!["../corpus/documentation_example.debug_ustr.txt"]
694 .assert_debug_eq(&fzn)
695 }
696
697 #[test]
698 fn test_print_flatzinc() {
699 let mut rdr = BufReader::new(
700 File::open(Path::new("./corpus/documentation_example.fzn.json")).unwrap(),
701 );
702 let mut content = String::new();
703 let _ = rdr.read_to_string(&mut content).unwrap();
704
705 let fzn: FlatZinc<&str> = serde_json::from_str(&content).unwrap();
706 expect_test::expect_file!["../corpus/documentation_example.fzn"]
707 .assert_eq(&fzn.to_string());
708
709 let ann: Annotation<&str> = Annotation::Call(AnnotationCall {
710 id: "bool_search",
711 args: vec![
712 AnnotationArgument::Literal(AnnotationLiteral::BaseLiteral(Literal::Identifier(
713 "input_order",
714 ))),
715 AnnotationArgument::Literal(AnnotationLiteral::BaseLiteral(Literal::Identifier(
716 "indomain_min",
717 ))),
718 ],
719 });
720 assert_eq!(ann.to_string(), "::bool_search(input_order, indomain_min)");
721
722 let dom = Domain::Float(RangeList::from(1.0..=4.0));
723 assert_eq!(dom.to_string(), "1.0..4.0");
724
725 let ty = Type::Bool;
726 assert_eq!(ty.to_string(), "bool");
727 let ty = Type::Int;
728 assert_eq!(ty.to_string(), "int");
729 let ty = Type::Float;
730 assert_eq!(ty.to_string(), "float");
731 let ty = Type::IntSet;
732 assert_eq!(ty.to_string(), "set of int");
733
734 let lit = Literal::<&str>::Int(1);
735 assert_eq!(lit.to_string(), "1");
736 let lit = Literal::<&str>::Float(1.0);
737 assert_eq!(lit.to_string(), "1.0");
738 let lit = Literal::<&str>::Identifier("x");
739 assert_eq!(lit.to_string(), "x");
740 let lit = Literal::<&str>::Bool(true);
741 assert_eq!(lit.to_string(), "true");
742 let lit = Literal::<&str>::IntSet(RangeList::from(2..=3));
743 assert_eq!(lit.to_string(), "2..3");
744 let lit = Literal::<&str>::FloatSet(RangeList::from(2.0..=3.0));
745 assert_eq!(lit.to_string(), "2.0..3.0");
746 let lit = Literal::<&str>::String(String::from("hello"));
747 assert_eq!(lit.to_string(), "\"hello\"");
748
749 let fzn = FlatZinc {
750 variables: BTreeMap::from([(
751 "x",
752 Variable {
753 ty: Type::IntSet,
754 domain: None,
755 ann: vec![Annotation::Atom("special")],
756 defined: false,
757 introduced: true,
758 value: Some(Literal::IntSet(RangeList::from(1..=4))),
759 },
760 )]),
761 arrays: BTreeMap::from([(
762 "y",
763 Array {
764 ann: vec![Annotation::Atom("special")],
765 contents: vec![Literal::Int(1), Literal::Int(2), Literal::Int(3)],
766 introduced: true,
767 defined: true,
768 },
769 )]),
770 output: vec!["y"],
771 ..Default::default()
772 };
773 assert_eq!(
774 fzn.to_string(),
775 "var set of int: x ::var_is_introduced ::special = 1..4;\narray[1..3] of int: y ::output_array([1..3]) ::is_defined_var ::var_is_introduced ::special = [1, 2, 3];\nsolve satisfy;\n"
776 );
777
778 let sat = SolveObjective {
779 method: Method::Minimize,
780 ann: vec![ann],
781 objective: Some(Literal::Identifier("x")),
782 };
783 assert_eq!(
784 sat.to_string(),
785 "solve ::bool_search(input_order, indomain_min) minimize x"
786 );
787 }
788}