1pub mod constraint;
56pub mod expression;
57
58use std::{
59 borrow::Cow,
60 fmt::{self, Display},
61 marker::PhantomData,
62 ops::RangeInclusive,
63 str::FromStr,
64};
65
66use nom::{
67 character::complete::{char, digit1},
68 combinator::{all_consuming, map_res, opt, recognize},
69 multi::many0,
70 sequence::delimited,
71 IResult, Parser,
72};
73pub use rangelist::RangeList;
74use serde::{de::Visitor, Deserialize, Deserializer, Serialize, Serializer};
75
76use crate::{
77 constraint::Constraint,
78 expression::{identifier, int, range, sequence, whitespace_seperated, IntExp},
79};
80
81#[derive(Clone, Debug, PartialEq, Hash)]
83pub struct Array<Identifier = String> {
84 pub identifier: Identifier,
86 pub note: Option<String>,
88 pub size: Vec<usize>,
90 pub domains: Vec<(Vec<VarRef<Identifier>>, RangeList<IntVal>)>,
98}
99
100#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
102#[serde(rename_all = "camelCase")]
103pub enum CombinationType {
104 #[default]
110 Lexico,
111 Pareto,
116}
117
118#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug, Deserialize, Serialize)]
125#[serde(rename_all = "UPPERCASE")]
126pub enum FrameworkType {
127 #[default]
132 Csp,
133 Cop,
140 Wcsp,
145 Fcsp,
153 Qcsp,
158 QcspPlus,
163 Qcop,
168 QcopPlus,
173 Scsp,
175 Scop,
177 Qstr,
179 Tcsp,
185 Ncsp,
190 Ncop,
194 DisCsp,
196 DisWcsp,
198}
199
200#[derive(Clone, Debug, PartialEq, Hash, Eq)]
202pub enum Indexing {
203 Single(IntVal),
205 Range(IntVal, IntVal),
207 Full,
209}
210
211#[derive(Clone, PartialEq, Debug, Hash)]
213pub struct Instance<Identifier = String> {
214 pub ty: FrameworkType,
216 pub variables: Vec<Variable<Identifier>>,
218 pub arrays: Vec<Array<Identifier>>,
220 pub constraints: Vec<Constraint<Identifier>>,
222 pub objectives: Objectives<Identifier>,
224}
225
226#[derive(Clone, Debug, PartialEq, Hash, Deserialize)]
231#[serde(bound(deserialize = "Identifier: FromStr"))]
232pub struct Instantiation<Identifier = String> {
233 #[serde(flatten)]
235 pub info: MetaInfo<Identifier>,
236 #[serde(rename = "@type", default, skip_serializing_if = "Option::is_none")]
242 pub ty: Option<InstantiationType>,
243 #[serde(rename = "@cost", default, skip_serializing_if = "Option::is_none")]
250 pub cost: Option<IntVal>,
251 #[serde(
252 deserialize_with = "VarRef::parse_vec",
253 serialize_with = "serialize_list"
254 )]
255 pub list: Vec<VarRef<Identifier>>,
257 #[serde(
259 deserialize_with = "deserialize_int_vals",
260 serialize_with = "serialize_list"
261 )]
262 pub values: Vec<IntVal>,
263}
264
265#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
267#[serde(rename_all = "camelCase")]
268pub enum InstantiationType {
269 Solution,
271 Optimum,
274}
275
276pub type IntVal = i64;
278
279#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
282#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
283pub struct MetaInfo<Identifier> {
284 #[serde(
286 rename = "@id",
287 default,
288 skip_serializing_if = "Option::is_none",
289 deserialize_with = "deserialize_ident",
290 serialize_with = "serialize_ident"
291 )]
292 pub identifier: Option<Identifier>,
293 #[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
295 pub note: Option<String>,
296}
297
298#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
300#[serde(
301 rename_all = "camelCase",
302 bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display")
303)]
304pub enum Objective<Identifier = String> {
305 #[serde(rename = "minimize")]
308 Minimize(ObjExp<Identifier>),
309 #[serde(rename = "maximize")]
312 Maximize(ObjExp<Identifier>),
313}
314
315#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
317#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
318pub struct Objectives<Identifier = String> {
319 #[serde(default, rename = "@combination")]
321 pub combination: CombinationType,
322 #[serde(rename = "$value")]
324 pub objectives: Vec<Objective<Identifier>>,
325}
326
327#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
329#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
330pub struct ObjExp<Identifier = String> {
331 #[serde(flatten)]
333 pub info: MetaInfo<Identifier>,
334 #[serde(alias = "@type", default)]
336 pub ty: ObjType,
337 #[serde(
339 alias = "$text",
340 deserialize_with = "IntExp::parse_vec",
341 serialize_with = "serialize_list"
342 )]
343 pub list: Vec<IntExp<Identifier>>,
344 #[serde(
346 default,
347 skip_serializing_if = "Vec::is_empty",
348 deserialize_with = "deserialize_int_vals",
349 serialize_with = "serialize_list"
350 )]
351 pub coeffs: Vec<IntVal>,
352}
353
354#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
356#[serde(rename_all = "camelCase")]
357pub enum ObjType {
358 #[default]
360 Sum,
361 Minimum,
363 Maximum,
365 NValues,
367 Lex,
369}
370
371#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
373#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
374pub struct Variable<Identifier = String> {
375 #[serde(
377 rename = "@id",
378 deserialize_with = "from_str",
379 serialize_with = "as_str"
380 )]
381 pub identifier: Identifier,
382 #[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
384 pub note: Option<String>,
385 #[serde(
387 rename = "$text",
388 deserialize_with = "deserialize_range_list",
389 serialize_with = "serialize_range_list"
390 )]
391 pub domain: RangeList<IntVal>,
392}
393
394#[derive(Clone, Debug, PartialEq, Hash, Eq)]
396pub enum VarRef<Identifier> {
397 Ident(Identifier),
399 ArrayAccess(Identifier, Vec<Indexing>),
401}
402
403fn as_str<S: Serializer, I: Display>(value: &I, serializer: S) -> Result<S::Ok, S::Error> {
405 serializer.serialize_str(&value.to_string())
406}
407
408fn collect_range_list<I: IntoIterator<Item = RangeInclusive<IntVal>>>(
410 iter: I,
411) -> RangeList<IntVal> {
412 let mut r: Vec<_> = iter.into_iter().collect();
413 r.sort_by_key(|i| *i.start());
414 let mut it = r.into_iter();
415 let mut ranges = Vec::new();
416 let mut cur = it.next().unwrap();
417 for next in it {
418 if *cur.end() >= (next.start() - 1) {
419 cur = *cur.start()..=*next.end()
420 } else {
421 ranges.push(cur);
422 cur = next;
423 }
424 }
425 ranges.push(cur);
426 ranges.into_iter().collect()
427}
428
429fn deserialize_ident<'de, D: Deserializer<'de>, Identifier: FromStr>(
431 deserializer: D,
432) -> Result<Option<Identifier>, D::Error> {
433 struct V<X>(PhantomData<X>);
435 impl<X: FromStr> Visitor<'_> for V<X> {
436 type Value = Option<X>;
437
438 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
439 formatter.write_str("an identfier")
440 }
441
442 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
443 let v = v.trim();
444 Ok(Some(FromStr::from_str(v).map_err(|_| {
445 E::custom("unable to create identifier from string")
446 })?))
447 }
448 }
449 let visitor = V::<Identifier>(PhantomData);
450 deserializer.deserialize_str(visitor)
451}
452
453fn deserialize_int_vals<'de, D: Deserializer<'de>>(
455 deserializer: D,
456) -> Result<Vec<IntVal>, D::Error> {
457 struct V;
459 impl Visitor<'_> for V {
460 type Value = Vec<IntVal>;
461
462 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
463 formatter.write_str("a list of integers")
464 }
465
466 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
467 let v = v.trim();
468 let (_, v) = all_consuming(whitespace_seperated(int))
469 .parse(v)
470 .map_err(|_| E::custom(format!("invalid list of integers {v}")))?;
471 Ok(v)
472 }
473 }
474 deserializer.deserialize_str(V)
475}
476
477fn deserialize_range_list<'de, D: Deserializer<'de>>(
479 deserializer: D,
480) -> Result<RangeList<IntVal>, D::Error> {
481 struct V;
483 impl Visitor<'_> for V {
484 type Value = RangeList<IntVal>;
485
486 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
487 formatter.write_str("a list of ranges")
488 }
489
490 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
491 let v = v.trim();
492 let (_, r) = all_consuming(whitespace_seperated(range))
493 .parse(v)
494 .map_err(|_| E::custom(format!("invalid list of ranges `{v}")))?;
495 Ok(collect_range_list(r))
496 }
497 }
498 let visitor = V;
499 deserializer.deserialize_str(visitor)
500}
501
502fn deserialize_size<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<usize>, D::Error> {
504 struct V;
506 impl Visitor<'_> for V {
507 type Value = Vec<usize>;
508
509 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
510 formatter.write_str("an array size expression")
511 }
512
513 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
514 let v = v.trim();
515 let (_, r) = all_consuming(sequence(delimited(
516 char::<_, nom::error::Error<&str>>('['),
517 map_res(recognize(digit1), str::parse),
518 char(']'),
519 )))
520 .parse(v)
521 .map_err(|_| E::custom(format!("invalid array size expression `{v}'")))?;
522 Ok(r)
523 }
524 }
525 let visitor = V;
526 deserializer.deserialize_str(visitor)
527}
528
529fn from_str<'de, D: Deserializer<'de>, I: FromStr>(deserializer: D) -> Result<I, D::Error> {
531 let s: Cow<'_, str> = Deserialize::deserialize(deserializer)?;
532 match s.trim().parse() {
533 Ok(t) => Ok(t),
534 Err(_) => Err(serde::de::Error::custom("unable to parse from string")),
535 }
536}
537
538fn serialize_list<S: Serializer, T: Display>(exps: &[T], serializer: S) -> Result<S::Ok, S::Error> {
541 serializer.serialize_str(
542 &exps
543 .iter()
544 .map(|e| format!("{}", e))
545 .collect::<Vec<_>>()
546 .join(" "),
547 )
548}
549
550fn serialize_ident<S: Serializer, Identifier: Display>(
552 identifier: &Option<Identifier>,
553 serializer: S,
554) -> Result<S::Ok, S::Error> {
555 serializer.serialize_str(&format!("{}", identifier.as_ref().unwrap()))
556}
557
558fn serialize_range_list<S: Serializer>(
560 exps: &RangeList<IntVal>,
561 serializer: S,
562) -> Result<S::Ok, S::Error> {
563 serializer.serialize_str(
564 &exps
565 .into_iter()
566 .map(|e| {
567 if e.start() == e.end() {
568 e.start().to_string()
569 } else {
570 format!("{}..{}", e.start(), e.end())
571 }
572 })
573 .collect::<Vec<_>>()
574 .join(" "),
575 )
576}
577
578fn serialize_size<S: Serializer>(exps: &[usize], serializer: S) -> Result<S::Ok, S::Error> {
580 serializer.serialize_str(
581 &exps
582 .iter()
583 .map(|e| format!("[{}]", e))
584 .collect::<Vec<_>>()
585 .join(""),
586 )
587}
588
589impl<'de, Identifier: FromStr> Deserialize<'de> for Array<Identifier> {
590 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
591 #[derive(Deserialize)]
593 #[serde(bound = "Identifier: FromStr")]
594 struct DomainStruct<Identifier: FromStr> {
595 #[serde(rename = "@for", deserialize_with = "VarRef::parse_vec")]
597 vars: Vec<VarRef<Identifier>>,
598 #[serde(rename = "$text", deserialize_with = "deserialize_range_list")]
600 domain: RangeList<IntVal>,
601 }
602 #[derive(Deserialize)]
604 #[serde(bound = "Identifier: FromStr")]
605 enum Domain<'a, Identifier: FromStr> {
606 #[serde(rename = "domain")]
608 Domain(Vec<DomainStruct<Identifier>>),
609 #[serde(rename = "$text")]
611 Direct(Cow<'a, str>),
612 }
613 #[derive(Deserialize)]
615 #[serde(bound = "Identifier: FromStr")]
616 struct Array<'a, Identifier: FromStr> {
617 #[serde(rename = "@id", deserialize_with = "from_str")]
619 identifier: Identifier,
620 #[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
622 note: Option<String>,
623 #[serde(rename = "@size", deserialize_with = "deserialize_size")]
625 size: Vec<usize>,
626 #[serde(rename = "$value")]
628 domain: Domain<'a, Identifier>,
629 }
630 let x = Array::deserialize(deserializer)?;
631 let domains = match x.domain {
632 Domain::Domain(v) => v.into_iter().map(|d| (d.vars, d.domain)).collect(),
633 Domain::Direct(s) => {
634 let s = s.trim();
635 let s = all_consuming(whitespace_seperated(range))
636 .parse(s.as_ref())
637 .map_err(|_| {
638 serde::de::Error::custom(format!("unable to parse ranges from `{s}'"))
639 })?;
640 vec![(
641 vec![VarRef::Ident(
642 Identifier::from_str("others").unwrap_or_else(|_| {
643 panic!("unable to create identifier from `\"others\"`")
644 }),
645 )],
646 collect_range_list(s.1),
647 )]
648 }
649 };
650 Ok(Self {
651 identifier: x.identifier,
652 note: x.note,
653 size: x.size,
654 domains,
655 })
656 }
657}
658
659impl<Identifier: Display> Serialize for Array<Identifier> {
660 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
661 #[derive(Serialize)]
663 #[serde(bound = "Identifier: Display")]
664 struct DomainStruct<'a, Identifier: Display> {
665 #[serde(rename = "@for", serialize_with = "serialize_list")]
667 vars: &'a Vec<VarRef<Identifier>>,
668 #[serde(rename = "$text", serialize_with = "serialize_range_list")]
670 domain: &'a RangeList<IntVal>,
671 }
672 #[derive(Serialize)]
674 #[serde(bound = "Identifier: Display")]
675 enum Domain<'a, Identifier: Display> {
676 #[serde(rename = "domain")]
678 Domain(DomainStruct<'a, Identifier>),
679 }
680 #[derive(Serialize)]
681 #[serde(bound = "Identifier: Display")]
682 struct Array<'a, Identifier: Display> {
683 #[serde(rename = "@id", serialize_with = "as_str")]
685 identifier: &'a Identifier,
686 #[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
688 note: &'a Option<String>,
689 #[serde(rename = "@size", serialize_with = "serialize_size")]
691 size: &'a Vec<usize>,
692 #[serde(rename = "$value")]
694 domain: Vec<Domain<'a, Identifier>>,
695 }
696 let domain = self
697 .domains
698 .iter()
699 .map(|(v, d)| Domain::Domain(DomainStruct { vars: v, domain: d }))
700 .collect();
701 let x = Array {
702 identifier: &self.identifier,
703 note: &self.note,
704 size: &self.size,
705 domain,
706 };
707 x.serialize(serializer)
708 }
709}
710
711impl<Identifier> Default for Instance<Identifier> {
712 fn default() -> Self {
713 Self {
714 ty: Default::default(),
715 variables: Default::default(),
716 arrays: Default::default(),
717 constraints: Default::default(),
718 objectives: Default::default(),
719 }
720 }
721}
722
723impl<'de, Identifier: Deserialize<'de> + FromStr> Deserialize<'de> for Instance<Identifier> {
724 fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
725 #[derive(Deserialize)]
727 enum V<Identifier: FromStr> {
728 #[serde(rename = "var")]
730 Variable(Variable<Identifier>),
731 #[serde(rename = "array")]
733 Array(Array<Identifier>),
734 }
735 #[derive(Deserialize)]
737 struct Variables<Identifier: FromStr = String> {
738 #[serde(rename = "$value")]
740 vars: Vec<V<Identifier>>,
741 }
742 #[derive(Deserialize)]
744 struct Constraints<Identifier: FromStr = String> {
745 #[serde(rename = "$value")]
747 content: Vec<Constraint<Identifier>>,
748 }
749 #[derive(Deserialize)]
751 struct Instance<Identifier: FromStr = String> {
752 #[serde(rename = "@type")]
754 ty: FrameworkType,
755 variables: Option<Variables<Identifier>>,
757 constraints: Option<Constraints<Identifier>>,
759 #[serde(default = "Objectives::default")]
761 objectives: Objectives<Identifier>,
762 }
763 let inst: Instance<Identifier> = Deserialize::deserialize(deserializer)?;
764 let mut variables = Vec::new();
765 let mut arrays = Vec::new();
766 for v in inst.variables.map(|v| v.vars).into_iter().flatten() {
767 match v {
768 V::Variable(var) => variables.push(var),
769 V::Array(arr) => arrays.push(arr),
770 }
771 }
772 Ok(Self {
773 ty: inst.ty,
774 variables,
775 arrays,
776 constraints: inst.constraints.map_or_else(Vec::new, |c| c.content),
777 objectives: inst.objectives,
778 })
779 }
780}
781
782impl<Identifier: Serialize + Display> Serialize for Instance<Identifier> {
783 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
784 #[derive(Serialize)]
786 struct Variables<'a, Identifier: Display> {
787 var: &'a Vec<Variable<Identifier>>,
789 array: &'a Vec<Array<Identifier>>,
791 }
792 impl<Identifier: Display> Variables<'_, Identifier> {
793 fn is_empty(&self) -> bool {
795 self.var.is_empty() && self.array.is_empty()
796 }
797 }
798 #[derive(Serialize)]
800 struct Constraints<'a, Identifier: Display> {
801 #[serde(rename = "$value")]
803 content: &'a Vec<Constraint<Identifier>>,
804 }
805 impl<Identifier: Display> Constraints<'_, Identifier> {
806 fn is_empty(&self) -> bool {
808 self.content.is_empty()
809 }
810 }
811 #[derive(Serialize)]
813 #[serde(rename = "instance")]
814 struct Instance<'a, Identifier: Display> {
815 #[serde(rename = "@type")]
817 ty: FrameworkType,
818 #[serde(skip_serializing_if = "Variables::is_empty")]
820 variables: Variables<'a, Identifier>,
821 #[serde(skip_serializing_if = "Constraints::is_empty")]
823 constraints: Constraints<'a, Identifier>,
824 #[serde(skip_serializing_if = "Objectives::is_empty")]
826 objectives: &'a Objectives<Identifier>,
827 }
828 let x = Instance {
829 ty: self.ty,
830 variables: Variables {
831 var: &self.variables,
832 array: &self.arrays,
833 },
834 constraints: Constraints {
835 content: &self.constraints,
836 },
837 objectives: &self.objectives,
838 };
839 Serialize::serialize(&x, serializer)
840 }
841}
842
843impl<Identifier: Display> Serialize for Instantiation<Identifier> {
846 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
847 #[derive(Serialize)]
849 #[serde(rename = "instantiation", bound(serialize = "Identifier: Display"))]
850 struct Instantiation<'a, Identifier = String> {
851 #[serde(
853 rename = "@id",
854 skip_serializing_if = "Option::is_none",
855 serialize_with = "serialize_ident"
856 )]
857 identifier: &'a Option<Identifier>,
858 #[serde(rename = "@note", skip_serializing_if = "Option::is_none")]
860 note: &'a Option<String>,
861 #[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
863 ty: &'a Option<InstantiationType>,
864 #[serde(rename = "@cost", skip_serializing_if = "Option::is_none")]
866 cost: &'a Option<IntVal>,
867 #[serde(serialize_with = "serialize_list")]
869 list: &'a Vec<VarRef<Identifier>>,
870 #[serde(serialize_with = "serialize_list")]
872 values: &'a Vec<IntVal>,
873 }
874 Instantiation {
875 identifier: &self.info.identifier,
876 note: &self.info.note,
877 ty: &self.ty,
878 cost: &self.cost,
879 list: &self.list,
880 values: &self.values,
881 }
882 .serialize(serializer)
883 }
884}
885
886impl<Identifier> Objectives<Identifier> {
887 pub fn is_empty(&self) -> bool {
889 self.objectives.is_empty()
890 }
891}
892
893impl<Identifier> Default for Objectives<Identifier> {
894 fn default() -> Self {
895 Self {
896 combination: CombinationType::default(),
897 objectives: Vec::new(),
898 }
899 }
900}
901
902impl<Identifier: FromStr> VarRef<Identifier> {
903 pub(crate) fn parse(input: &str) -> IResult<&str, Self> {
905 let (input, ident) = identifier(input)?;
906 let (input, v) = many0(delimited(char('['), opt(range), char(']'))).parse(input)?;
907 Ok((
908 input,
909 if v.is_empty() {
910 VarRef::Ident(ident)
911 } else {
912 let v = v
913 .into_iter()
914 .map(|r| {
915 r.map(|r| {
916 if r.start() == r.end() {
917 Indexing::Single(*r.start())
918 } else {
919 Indexing::Range(*r.start(), *r.end())
920 }
921 })
922 .unwrap_or(Indexing::Full)
923 })
924 .collect();
925 VarRef::ArrayAccess(ident, v)
926 },
927 ))
928 }
929
930 fn parse_vec<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<Self>, D::Error> {
932 struct V<X>(PhantomData<X>);
934 impl<X: FromStr> Visitor<'_> for V<X> {
935 type Value = Vec<VarRef<X>>;
936
937 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
938 formatter.write_str("a list of variable references")
939 }
940
941 fn visit_str<E: serde::de::Error>(self, v: &str) -> Result<Self::Value, E> {
942 let v = v.trim();
943 let (_, v) = all_consuming(whitespace_seperated(VarRef::parse))
944 .parse(v)
945 .map_err(|_| E::custom(format!("invalid variable references `{v}'")))?;
946 Ok(v)
947 }
948 }
949 let visitor = V::<Identifier>(PhantomData);
950 deserializer.deserialize_str(visitor)
951 }
952}
953
954impl<Identifier: Display> Display for VarRef<Identifier> {
955 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
956 match self {
957 VarRef::Ident(ident) => ident.fmt(f),
958 VarRef::ArrayAccess(ident, v) => {
959 write!(
960 f,
961 "{}{}",
962 ident,
963 v.iter()
964 .map(|i| format!(
965 "[{}]",
966 match i {
967 Indexing::Single(v) => v.to_string(),
968 Indexing::Range(a, b) => format!("{}..{}", a, b),
969 Indexing::Full => String::new(),
970 }
971 ))
972 .collect::<Vec<_>>()
973 .join("")
974 )
975 }
976 }
977 }
978}
979
980#[cfg(test)]
981mod tests {
982 use std::{fmt::Debug, fs::File, io::BufReader, path::Path};
983
984 use expect_test::ExpectFile;
985 use serde::{de::DeserializeOwned, Serialize};
986
987 use crate::{Instance, Instantiation};
988
989 fn test_successful_serialization<T: Debug + DeserializeOwned + Serialize + PartialEq>(
990 file: &Path,
991 exp: ExpectFile,
992 ) {
993 let rdr = BufReader::new(File::open(file).unwrap());
994 let inst: T = quick_xml::de::from_reader(rdr).unwrap();
995 exp.assert_debug_eq(&inst);
996 let output = quick_xml::se::to_string(&inst).unwrap();
997 let inst2: T = quick_xml::de::from_str(&output).unwrap();
998 assert_eq!(inst, inst2)
999 }
1000
1001 macro_rules! test_file {
1002 ($file:ident) => {
1003 test_file!($file, Instance);
1004 };
1005 ($file:ident, $t:ident) => {
1006 #[test]
1007 fn $file() {
1008 test_successful_serialization::<$t>(
1009 std::path::Path::new(&format!("./corpus/{}.xml", stringify!($file))),
1010 expect_test::expect_file![&format!(
1011 "../corpus/{}.debug.txt",
1012 stringify!($file)
1013 )],
1014 )
1015 }
1016 };
1017 }
1018 pub(crate) use test_file;
1019
1020 test_file!(knapsack);
1021
1022 test_file!(xcsp3_ex_001);
1023 test_file!(xcsp3_ex_002);
1024 test_file!(xcsp3_ex_004);
1026 test_file!(xcsp3_ex_005);
1027 test_file!(xcsp3_ex_006);
1028 test_file!(xcsp3_ex_007);
1029 test_file!(xcsp3_ex_018);
1040 test_file!(xcsp3_ex_019);
1041 test_file!(xcsp3_ex_021);
1043 test_file!(xcsp3_ex_022);
1044 test_file!(xcsp3_ex_023, Instantiation);
1045 test_file!(xcsp3_ex_024);
1046 test_file!(xcsp3_ex_025, Instantiation);
1047 test_file!(xcsp3_ex_027, Instantiation);
1049 test_file!(xcsp3_ex_029);
1051 test_file!(xcsp3_ex_030);
1052 test_file!(xcsp3_ex_031);
1053 test_file!(xcsp3_ex_032);
1054 test_file!(xcsp3_ex_033);
1055 test_file!(xcsp3_ex_034);
1056 test_file!(xcsp3_ex_035);
1057 test_file!(xcsp3_ex_036);
1058 test_file!(xcsp3_ex_037);
1059 test_file!(xcsp3_ex_041);
1063 test_file!(xcsp3_ex_043);
1065 test_file!(xcsp3_ex_044);
1066 test_file!(xcsp3_ex_045);
1067 test_file!(xcsp3_ex_046);
1068 test_file!(xcsp3_ex_047);
1069 test_file!(xcsp3_ex_049);
1071 test_file!(xcsp3_ex_051);
1073 test_file!(xcsp3_ex_052);
1074 test_file!(xcsp3_ex_053);
1075 test_file!(xcsp3_ex_055);
1077 test_file!(xcsp3_ex_056);
1078 test_file!(xcsp3_ex_057);
1079 test_file!(xcsp3_ex_058);
1080 test_file!(xcsp3_ex_059);
1081 test_file!(xcsp3_ex_060);
1082 test_file!(xcsp3_ex_063);
1085 test_file!(xcsp3_ex_064);
1086 test_file!(xcsp3_ex_065);
1087 test_file!(xcsp3_ex_066);
1088 test_file!(xcsp3_ex_067);
1089 test_file!(xcsp3_ex_068);
1090 test_file!(xcsp3_ex_069);
1091 test_file!(xcsp3_ex_072);
1094 test_file!(xcsp3_ex_074);
1096 test_file!(xcsp3_ex_075);
1097 test_file!(xcsp3_ex_076);
1098 test_file!(xcsp3_ex_077);
1099 test_file!(xcsp3_ex_078);
1100 test_file!(xcsp3_ex_085);
1107 test_file!(xcsp3_ex_086);
1108 test_file!(xcsp3_ex_089);
1111 test_file!(xcsp3_ex_091);
1113 test_file!(xcsp3_ex_097);
1119 test_file!(xcsp3_ex_100);
1122 test_file!(xcsp3_ex_101);
1123 test_file!(xcsp3_ex_167);
1189 }