xcsp3_serde/
lib.rs

1//! Serialization of the XCSP3 (core) format
2//!
3//! XCSP3 is an integrated format for representing combinatorial constrained
4//! problems, which can deal with mono/multi optimization, many types of
5//! variables, cost functions, reification, views, annotations, variable
6//! quantification, distributed, probabilistic and qualitative reasoning. It is
7//! also compact, and easy to read and to parse. The objective of XCSP3 is to
8//! ease the effort required to test and compare different algorithms by
9//! providing a common test-bed of combinatorial constrained instances.
10//!
11//! This crate focuses on the (de-)serializeation of the XCSP3 format. It can be
12//! used to parse an XCSP3 XML file into the provided rust types, or writing the
13//! provided rust types to an XCSP3 XML file.
14//!
15//! # Getting Started
16//!
17//! Install `xcsp3-serde` and `quick-xml` for your package:
18//!
19//! ```bash
20//! cargo add xcsp3-serde quick-xml
21//! ```
22//!
23//! Once these dependencies have been installed to your crate, you could
24//! deserialize a XCSP3 XML file as follows:
25//!
26//! ```
27//! # use xcsp3_serde::Instance;
28//! # use std::{fs::File, io::BufReader, path::Path};
29//! # let path = Path::new("corpus/xcsp3_ex_001.xml");
30//! // let path = Path::new("/lorem/ipsum/instance.xml");
31//! let rdr = BufReader::new(File::open(path).unwrap());
32//! let instance: Instance = quick_xml::de::from_reader(rdr).unwrap();
33//! // ... process XCSP3 ...
34//! ```
35//!
36//! If, however, you want to serialize a XCSP3 instance you could follow the
37//! following fragment:
38//!
39//! ```
40//! # use xcsp3_serde::Instance;
41//! let instance = Instance::<String>::default();
42//! // ... create XCSP3 instance ...
43//! let xml_str = quick_xml::se::to_string(&instance).unwrap();
44//! ```
45//! Note that `quick_xml::se::to_writer`, using a buffered file writer, would be
46//! preferred when writing larger instances.
47//!
48//! # Limitations
49//!
50//! Not all XCSP3 features are currently implemented, the functionality of
51//! XCSP3-core is generally implemented and supported. This allows users to work
52//! with the most common constraint types and representations. Future updates
53//! will focus on expanding the range of supported XCSP3 features.
54
55pub 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/// Definition of a k-dimensional arrays of variables
82#[derive(Clone, Debug, PartialEq, Hash)]
83pub struct Array<Identifier = String> {
84	/// Name used to refer to the array
85	pub identifier: Identifier,
86	/// Comment by the user
87	pub note: Option<String>,
88	/// Dimensions of the array
89	pub size: Vec<usize>,
90	/// Domains of the variables contained within the array
91	///
92	/// Note that when several subsets of variables of an array have different
93	/// domains, a rangelist is provided for each of these subsets. The first
94	/// member of the tuple indicates the list of variables to which the domain
95	/// definition applies. The special identifier `others` is used to declare a
96	/// default domain for all other variables contained in the array.
97	pub domains: Vec<(Vec<VarRef<Identifier>>, RangeList<IntVal>)>,
98}
99
100/// The way in which combinations of objectives are to be evaluated
101#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
102#[serde(rename_all = "camelCase")]
103pub enum CombinationType {
104	/// Objectives are lexicographically ordered
105	///
106	/// A solution is superceeded if it is better in the first objective, or if it
107	/// is equal in the first objective and better in the second objective, and so
108	/// on.
109	#[default]
110	Lexico,
111	/// No objective is more important than another one
112	///
113	/// A solution is better than another if it is better in at least one
114	/// objective and not worse in any other objective.
115	Pareto,
116}
117
118/// The framework of an XCSP3 instance
119///
120/// The framework of an XCSP3 instance is used to determine the types of
121/// constraints and variables that can be used in the instance. Different
122/// frameworks correspond to different types of problems that can be expressed
123/// in XCSP3.
124#[derive(Default, Clone, Copy, PartialEq, Eq, Hash, Debug, Deserialize, Serialize)]
125#[serde(rename_all = "UPPERCASE")]
126pub enum FrameworkType {
127	/// Constraint Satisfaction Problem
128	///
129	/// A discrete Constraint Network that constains a finite set of variables and
130	/// a finite set of constraints.
131	#[default]
132	Csp,
133	/// Constraint Optimization Problem
134	///
135	/// An instance is defined by a set of variables, a set of constraints, as for
136	/// [`FrameworkType::Csp`], together with a set of objective functions.
137	/// Mono-objective optimization is when only one objective function is
138	/// present. Otherwise, this is multi-objective optimization.
139	Cop,
140	/// Weighted Constraint Satisfaction Problem
141	///
142	/// An extension to [`FrameworkType::Csp`] that relies on a valuation
143	/// structure using weighted constraints.
144	Wcsp,
145	/// Fuzzy Constraint Satisfaction Problem
146	///
147	/// An extension of [`FrameworkType::Csp`] with fuzzy constraints. Each fuzzy
148	/// constraint represents a fuzzy relation on its scope: it associates a value
149	/// in \[0,1\], called membership degree, with each constraint tuple,
150	/// indicating to what extent the tuple belongs to the relation and therefore
151	/// satisfies the constraint.
152	Fcsp,
153	/// Quantified Constraint Satisfaction Problem
154	///
155	/// An extension of [`FrameworkType::Csp`] in which variables may be
156	/// quantified universally or existentially.
157	Qcsp,
158	/// Extended Quantified Constraint Optimization Problem
159	///
160	/// An extension of [`FrameworkType::Qcsp`] to overcome some difficulties that
161	/// may occur when modeling real problems with classical QCSP.
162	QcspPlus,
163	/// Quantified Constraint Optimization Problem
164	///
165	/// An extesion of [`FrameworkType::Qcsp`] that allows us to formally express
166	/// preferences over [`FrameworkType::Qcsp`] strategies
167	Qcop,
168	/// Extended Quantified Constraint Optimization Problem
169	///
170	/// An extesion of [`FrameworkType::QcspPlus`] that allows us to formally
171	/// express preferences over [`FrameworkType::QcspPlus`] strategies
172	QcopPlus,
173	/// Stochastic Constraint Satisfaction Problem
174	Scsp,
175	/// Stochastic Constraint Optimization Problem
176	Scop,
177	/// Qualitative Spatial Temporal Reasoning
178	Qstr,
179	/// Temporal Constraint Satisfaction Problem
180	///
181	/// In this framework, variables represent time points and temporal
182	/// information is represented by a set of unary and binary constraints, each
183	/// specifying a set of permitted intervals.
184	Tcsp,
185	/// Numerical Constraint Satisfaction Problem
186	///
187	/// An extension of [`FrameworkType::Csp`] in which variables are real numbers
188	/// and constraints are relations between these variables.
189	Ncsp,
190	/// Numerical Constraint Optimization Problem
191	///
192	/// An extension of [`FrameworkType::Ncsp`] that includes objective functions.
193	Ncop,
194	/// Distributed Constraint Satisfaction Problem
195	DisCsp,
196	/// Distributed Weighted Constraint Satisfaction Problem
197	DisWcsp,
198}
199
200/// An expression used to access a single element or a larger part of an array
201#[derive(Clone, Debug, PartialEq, Hash, Eq)]
202pub enum Indexing {
203	/// Accessing a single index of a dimension in an array
204	Single(IntVal),
205	/// Accessing a slice of a dimension in an array
206	Range(IntVal, IntVal),
207	/// Accessing the full range of an array
208	Full,
209}
210
211/// XCSP3 problem instance
212#[derive(Clone, PartialEq, Debug, Hash)]
213pub struct Instance<Identifier = String> {
214	/// The type of the framework used to express the instance.
215	pub ty: FrameworkType,
216	/// Definitions of the single decision variables
217	pub variables: Vec<Variable<Identifier>>,
218	/// Definitions of the arrays of decision variables
219	pub arrays: Vec<Array<Identifier>>,
220	/// Constraints that must be satisfied for a solution to be valid
221	pub constraints: Vec<Constraint<Identifier>>,
222	/// The objectives to be optimized
223	pub objectives: Objectives<Identifier>,
224}
225
226/// An assignment from a list of variables to a list of values
227///
228/// This structure is used both to represent an elementary constraint in an
229/// instance, and to represent the solution to an instance.
230#[derive(Clone, Debug, PartialEq, Hash, Deserialize)]
231#[serde(bound(deserialize = "Identifier: FromStr"))]
232pub struct Instantiation<Identifier = String> {
233	/// Optional metadata for the constraint
234	#[serde(flatten)]
235	pub info: MetaInfo<Identifier>,
236	/// The type of instantiation
237	///
238	/// This field is used to distinguish between different types of solutions,
239	/// and signal whether the solution is optimal or not. When this type is used
240	/// as a constraint, then this field is ignore and can be set to `None`.
241	#[serde(rename = "@type", default, skip_serializing_if = "Option::is_none")]
242	pub ty: Option<InstantiationType>,
243	/// The objective cost of the instantiation
244	///
245	/// This field is used to represent the cost of a solution, and is only used
246	/// when the instantiation type is used to represent a solution. When this
247	/// type is used as a constraint, then this field is ignore and can be set to
248	/// `None`.
249	#[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	/// List of variables that are assigned values
256	pub list: Vec<VarRef<Identifier>>,
257	/// List of values assigned to the variables
258	#[serde(
259		deserialize_with = "deserialize_int_vals",
260		serialize_with = "serialize_list"
261	)]
262	pub values: Vec<IntVal>,
263}
264
265/// The type of instantiation
266#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
267#[serde(rename_all = "camelCase")]
268pub enum InstantiationType {
269	/// A solution that satisfies all constraints
270	Solution,
271	/// A solution that satisfies all constraints and is optimal with regards to
272	/// the objective function(s)
273	Optimum,
274}
275
276/// Type used to represent integer values
277pub type IntVal = i64;
278
279/// Type used to capture optional metadata that can be attached to most XCSP3
280/// elements
281#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
282#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
283pub struct MetaInfo<Identifier> {
284	/// Name assigned to the element
285	#[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	/// Comment from the user about the element
294	#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
295	pub note: Option<String>,
296}
297
298/// Objective function
299#[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	/// An objective function where the goal is to find the smallest possible
306	/// value.
307	#[serde(rename = "minimize")]
308	Minimize(ObjExp<Identifier>),
309	/// An objective function where the goal is to find the largest possible
310	/// value.
311	#[serde(rename = "maximize")]
312	Maximize(ObjExp<Identifier>),
313}
314
315/// Collection of objective functions
316#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
317#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
318pub struct Objectives<Identifier = String> {
319	/// Combinator to aggregate multiple objectives
320	#[serde(default, rename = "@combination")]
321	pub combination: CombinationType,
322	/// List of objectives functions
323	#[serde(rename = "$value")]
324	pub objectives: Vec<Objective<Identifier>>,
325}
326
327/// Expression used to represent an objective function
328#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
329#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
330pub struct ObjExp<Identifier = String> {
331	/// Optional metadata for the objective
332	#[serde(flatten)]
333	pub info: MetaInfo<Identifier>,
334	/// Evaluation method for the list of expressions
335	#[serde(alias = "@type", default)]
336	pub ty: ObjType,
337	/// List of expressions
338	#[serde(
339		alias = "$text",
340		deserialize_with = "IntExp::parse_vec",
341		serialize_with = "serialize_list"
342	)]
343	pub list: Vec<IntExp<Identifier>>,
344	/// List of coefficients to apply to the expressions
345	#[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/// Evaluation method for the list of expressions in an objective function
355#[derive(Clone, Debug, Default, PartialEq, Hash, Deserialize, Serialize)]
356#[serde(rename_all = "camelCase")]
357pub enum ObjType {
358	/// Sum of the expressions
359	#[default]
360	Sum,
361	/// Minimum value of the expressions
362	Minimum,
363	/// Maximum value of the expressions
364	Maximum,
365	/// Number of different values among the expressions
366	NValues,
367	/// Lexico order of the expressions
368	Lex,
369}
370
371/// Definition of a variable
372#[derive(Clone, Debug, PartialEq, Hash, Deserialize, Serialize)]
373#[serde(bound(deserialize = "Identifier: FromStr", serialize = "Identifier: Display"))]
374pub struct Variable<Identifier = String> {
375	/// Name of the variable
376	#[serde(
377		rename = "@id",
378		deserialize_with = "from_str",
379		serialize_with = "as_str"
380	)]
381	pub identifier: Identifier,
382	/// Comment by the user about the variable
383	#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
384	pub note: Option<String>,
385	/// List of possible values the variable can take
386	#[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/// Reference to a variable, array element, or array slice
395#[derive(Clone, Debug, PartialEq, Hash, Eq)]
396pub enum VarRef<Identifier> {
397	/// Reference to a variable
398	Ident(Identifier),
399	/// Reference to an array element or slice
400	ArrayAccess(Identifier, Vec<Indexing>),
401}
402
403/// Serialize the value by converting it to a string
404fn as_str<S: Serializer, I: Display>(value: &I, serializer: S) -> Result<S::Ok, S::Error> {
405	serializer.serialize_str(&value.to_string())
406}
407
408/// Combine a list of integer ranges into a single range list
409fn 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
429/// Deserialize a string as an identifier
430fn deserialize_ident<'de, D: Deserializer<'de>, Identifier: FromStr>(
431	deserializer: D,
432) -> Result<Option<Identifier>, D::Error> {
433	/// Visitor to deserialize a string as an identifier
434	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
453/// Deserialize a string as a list of integers
454fn deserialize_int_vals<'de, D: Deserializer<'de>>(
455	deserializer: D,
456) -> Result<Vec<IntVal>, D::Error> {
457	/// Visitor to parse a list of integers
458	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
477/// Deserialize a string as a range list
478fn deserialize_range_list<'de, D: Deserializer<'de>>(
479	deserializer: D,
480) -> Result<RangeList<IntVal>, D::Error> {
481	/// Visitor for deserializing a range list
482	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
502/// Deserialize a string as a size expression
503fn deserialize_size<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<usize>, D::Error> {
504	/// Visitor for deserializing a size expression
505	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
529/// Deserialize a string and call the `FromStr` implementation
530fn 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
538/// Serialize a list of values by printing them to strings and joining them with
539/// spaces
540fn 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
550/// Serialize an optional identifier as a string
551fn 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
558/// Serialize a list of integers as a string of ranges separated by spaces
559fn 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
578/// Serialize a list of dimensions as a string size expression
579fn 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		/// Helper struct to deserialize the content of the <domain> element
592		#[derive(Deserialize)]
593		#[serde(bound = "Identifier: FromStr")]
594		struct DomainStruct<Identifier: FromStr> {
595			/// for attribute
596			#[serde(rename = "@for", deserialize_with = "VarRef::parse_vec")]
597			vars: Vec<VarRef<Identifier>>,
598			/// content of element
599			#[serde(rename = "$text", deserialize_with = "deserialize_range_list")]
600			domain: RangeList<IntVal>,
601		}
602		/// Helper enum to deserialize the content of the <array> element
603		#[derive(Deserialize)]
604		#[serde(bound = "Identifier: FromStr")]
605		enum Domain<'a, Identifier: FromStr> {
606			/// multiple <domain> elements
607			#[serde(rename = "domain")]
608			Domain(Vec<DomainStruct<Identifier>>),
609			/// single string content
610			#[serde(rename = "$text")]
611			Direct(Cow<'a, str>),
612		}
613		/// Helper struct to deserialize an <array> element
614		#[derive(Deserialize)]
615		#[serde(bound = "Identifier: FromStr")]
616		struct Array<'a, Identifier: FromStr> {
617			/// id attribute
618			#[serde(rename = "@id", deserialize_with = "from_str")]
619			identifier: Identifier,
620			/// optional note attribute
621			#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
622			note: Option<String>,
623			/// size attribute
624			#[serde(rename = "@size", deserialize_with = "deserialize_size")]
625			size: Vec<usize>,
626			/// content of the element
627			#[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		/// Helper struct to serialize the domain expression
662		#[derive(Serialize)]
663		#[serde(bound = "Identifier: Display")]
664		struct DomainStruct<'a, Identifier: Display> {
665			/// Variable references serialized as the for attribute
666			#[serde(rename = "@for", serialize_with = "serialize_list")]
667			vars: &'a Vec<VarRef<Identifier>>,
668			/// RangeList serialized as the string content of the element
669			#[serde(rename = "$text", serialize_with = "serialize_range_list")]
670			domain: &'a RangeList<IntVal>,
671		}
672		/// Domain expression serialized as the <domain> elements
673		#[derive(Serialize)]
674		#[serde(bound = "Identifier: Display")]
675		enum Domain<'a, Identifier: Display> {
676			/// Domain expression serialized as the <domain> elements
677			#[serde(rename = "domain")]
678			Domain(DomainStruct<'a, Identifier>),
679		}
680		#[derive(Serialize)]
681		#[serde(bound = "Identifier: Display")]
682		struct Array<'a, Identifier: Display> {
683			/// Identifier serialized as the id attribute
684			#[serde(rename = "@id", serialize_with = "as_str")]
685			identifier: &'a Identifier,
686			/// String serialized as the note attribute
687			#[serde(rename = "@note", default, skip_serializing_if = "Option::is_none")]
688			note: &'a Option<String>,
689			/// Size expression serialized as the size attribute
690			#[serde(rename = "@size", serialize_with = "serialize_size")]
691			size: &'a Vec<usize>,
692			/// Domain expressions serialized as the element content
693			#[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		/// Deserialized content of <variables> element
726		#[derive(Deserialize)]
727		enum V<Identifier: FromStr> {
728			/// Deserialized <var> element
729			#[serde(rename = "var")]
730			Variable(Variable<Identifier>),
731			/// Deserialized <array> element
732			#[serde(rename = "array")]
733			Array(Array<Identifier>),
734		}
735		/// Deserialized <variables> element
736		#[derive(Deserialize)]
737		struct Variables<Identifier: FromStr = String> {
738			/// Deserialized content of <variables> element
739			#[serde(rename = "$value")]
740			vars: Vec<V<Identifier>>,
741		}
742		/// Deserialized <constraints> element
743		#[derive(Deserialize)]
744		struct Constraints<Identifier: FromStr = String> {
745			/// Deserialized content of <constraints> element
746			#[serde(rename = "$value")]
747			content: Vec<Constraint<Identifier>>,
748		}
749		/// Deserialized <instance> element
750		#[derive(Deserialize)]
751		struct Instance<Identifier: FromStr = String> {
752			/// Deserialized type attribute
753			#[serde(rename = "@type")]
754			ty: FrameworkType,
755			/// Deserialized <variables> element
756			variables: Option<Variables<Identifier>>,
757			/// Deserialized <constraints> element
758			constraints: Option<Constraints<Identifier>>,
759			/// Deserialized <objectives> element
760			#[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		/// Helper struct to serialize the <variables> element
785		#[derive(Serialize)]
786		struct Variables<'a, Identifier: Display> {
787			/// Values serialized as <var> elements
788			var: &'a Vec<Variable<Identifier>>,
789			/// Values serialized as <array> elements
790			array: &'a Vec<Array<Identifier>>,
791		}
792		impl<Identifier: Display> Variables<'_, Identifier> {
793			/// Check whether there are any variables or arrays to serialize
794			fn is_empty(&self) -> bool {
795				self.var.is_empty() && self.array.is_empty()
796			}
797		}
798		/// Helper struct to serialize the <constraints> element
799		#[derive(Serialize)]
800		struct Constraints<'a, Identifier: Display> {
801			/// Constraints to be serialized
802			#[serde(rename = "$value")]
803			content: &'a Vec<Constraint<Identifier>>,
804		}
805		impl<Identifier: Display> Constraints<'_, Identifier> {
806			/// Check whether there are any constraints to serialize
807			fn is_empty(&self) -> bool {
808				self.content.is_empty()
809			}
810		}
811		/// Helper struct to serialize the <instance> element
812		#[derive(Serialize)]
813		#[serde(rename = "instance")]
814		struct Instance<'a, Identifier: Display> {
815			/// Value serialized as the type attribute
816			#[serde(rename = "@type")]
817			ty: FrameworkType,
818			/// Value serialized as the <variables> element
819			#[serde(skip_serializing_if = "Variables::is_empty")]
820			variables: Variables<'a, Identifier>,
821			/// Value serialized as the <constraints> element
822			#[serde(skip_serializing_if = "Constraints::is_empty")]
823			constraints: Constraints<'a, Identifier>,
824			/// Value serialized as the <objectives> element
825			#[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
843// Note: flatten of MetaInfo does not seem to work here
844// (https://github.com/tafia/quick-xml/issues/761)
845impl<Identifier: Display> Serialize for Instantiation<Identifier> {
846	fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
847		/// Helper struct to serialize the instantiation element
848		#[derive(Serialize)]
849		#[serde(rename = "instantiation", bound(serialize = "Identifier: Display"))]
850		struct Instantiation<'a, Identifier = String> {
851			/// Value serialized as the id attribute
852			#[serde(
853				rename = "@id",
854				skip_serializing_if = "Option::is_none",
855				serialize_with = "serialize_ident"
856			)]
857			identifier: &'a Option<Identifier>,
858			/// Value serialized as the note attribute
859			#[serde(rename = "@note", skip_serializing_if = "Option::is_none")]
860			note: &'a Option<String>,
861			/// Value serialized as the type attribute
862			#[serde(rename = "@type", skip_serializing_if = "Option::is_none")]
863			ty: &'a Option<InstantiationType>,
864			/// Value serialized as the cost attribute
865			#[serde(rename = "@cost", skip_serializing_if = "Option::is_none")]
866			cost: &'a Option<IntVal>,
867			/// Variable references serialized as <list>
868			#[serde(serialize_with = "serialize_list")]
869			list: &'a Vec<VarRef<Identifier>>,
870			/// Values serialized as <values>
871			#[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	/// Check whether there are no objectives.
888	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	/// Parse a variable reference.
904	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	/// Parse a list of variable references.
931	fn parse_vec<'de, D: Deserializer<'de>>(deserializer: D) -> Result<Vec<Self>, D::Error> {
932		/// Visitor for parsing a list of variable references.
933		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_003);
1025	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_008);
1030	// test_file!(xcsp3_ex_009);
1031	// test_file!(xcsp3_ex_010);
1032	// test_file!(xcsp3_ex_011);
1033	// test_file!(xcsp3_ex_012);
1034	// test_file!(xcsp3_ex_013);
1035	// test_file!(xcsp3_ex_014);
1036	// test_file!(xcsp3_ex_015);
1037	// test_file!(xcsp3_ex_016);
1038	// test_file!(xcsp3_ex_017);
1039	test_file!(xcsp3_ex_018);
1040	test_file!(xcsp3_ex_019);
1041	// test_file!(xcsp3_ex_020);
1042	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_026, Instantiation);
1048	test_file!(xcsp3_ex_027, Instantiation);
1049	// test_file!(xcsp3_ex_028, Instantiation);
1050	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_038);
1060	// test_file!(xcsp3_ex_039);
1061	// test_file!(xcsp3_ex_040);
1062	test_file!(xcsp3_ex_041);
1063	// test_file!(xcsp3_ex_042);
1064	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_048);
1070	test_file!(xcsp3_ex_049);
1071	// test_file!(xcsp3_ex_050);
1072	test_file!(xcsp3_ex_051);
1073	test_file!(xcsp3_ex_052);
1074	test_file!(xcsp3_ex_053);
1075	// test_file!(xcsp3_ex_054);
1076	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_061);
1083	// test_file!(xcsp3_ex_062);
1084	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_070);
1092	// test_file!(xcsp3_ex_071);
1093	test_file!(xcsp3_ex_072);
1094	// test_file!(xcsp3_ex_073);
1095	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_079);
1101	// test_file!(xcsp3_ex_080);
1102	// test_file!(xcsp3_ex_081);
1103	// test_file!(xcsp3_ex_082);
1104	// test_file!(xcsp3_ex_083);
1105	// test_file!(xcsp3_ex_084);
1106	test_file!(xcsp3_ex_085);
1107	test_file!(xcsp3_ex_086);
1108	// test_file!(xcsp3_ex_087);
1109	// test_file!(xcsp3_ex_088);
1110	test_file!(xcsp3_ex_089);
1111	// test_file!(xcsp3_ex_090);
1112	test_file!(xcsp3_ex_091);
1113	// test_file!(xcsp3_ex_092);
1114	// test_file!(xcsp3_ex_093);
1115	// test_file!(xcsp3_ex_094);
1116	// test_file!(xcsp3_ex_095);
1117	// test_file!(xcsp3_ex_096);
1118	test_file!(xcsp3_ex_097);
1119	// test_file!(xcsp3_ex_098);
1120	// test_file!(xcsp3_ex_099);
1121	test_file!(xcsp3_ex_100);
1122	test_file!(xcsp3_ex_101);
1123	// test_file!(xcsp3_ex_102);
1124	// test_file!(xcsp3_ex_103);
1125	// test_file!(xcsp3_ex_104);
1126	// test_file!(xcsp3_ex_105);
1127	// test_file!(xcsp3_ex_106);
1128	// test_file!(xcsp3_ex_107);
1129	// test_file!(xcsp3_ex_108);
1130	// test_file!(xcsp3_ex_109);
1131	// test_file!(xcsp3_ex_110);
1132	// test_file!(xcsp3_ex_111);
1133	// test_file!(xcsp3_ex_112);
1134	// test_file!(xcsp3_ex_113);
1135	// test_file!(xcsp3_ex_114);
1136	// test_file!(xcsp3_ex_115);
1137	// test_file!(xcsp3_ex_116);
1138	// test_file!(xcsp3_ex_117);
1139	// test_file!(xcsp3_ex_118);
1140	// test_file!(xcsp3_ex_119);
1141	// test_file!(xcsp3_ex_120);
1142	// test_file!(xcsp3_ex_121);
1143	// test_file!(xcsp3_ex_122);
1144	// test_file!(xcsp3_ex_123);
1145	// test_file!(xcsp3_ex_124);
1146	// test_file!(xcsp3_ex_125);
1147	// test_file!(xcsp3_ex_126);
1148	// test_file!(xcsp3_ex_127);
1149	// test_file!(xcsp3_ex_128);
1150	// test_file!(xcsp3_ex_129);
1151	// test_file!(xcsp3_ex_130);
1152	// test_file!(xcsp3_ex_131);
1153	// test_file!(xcsp3_ex_132);
1154	// test_file!(xcsp3_ex_133);
1155	// test_file!(xcsp3_ex_134);
1156	// test_file!(xcsp3_ex_135);
1157	// test_file!(xcsp3_ex_136);
1158	// test_file!(xcsp3_ex_137);
1159	// test_file!(xcsp3_ex_138);
1160	// test_file!(xcsp3_ex_139);
1161	// test_file!(xcsp3_ex_140);
1162	// test_file!(xcsp3_ex_141);
1163	// test_file!(xcsp3_ex_142);
1164	// test_file!(xcsp3_ex_143);
1165	// test_file!(xcsp3_ex_144);
1166	// test_file!(xcsp3_ex_145);
1167	// test_file!(xcsp3_ex_146);
1168	// test_file!(xcsp3_ex_147);
1169	// test_file!(xcsp3_ex_148);
1170	// test_file!(xcsp3_ex_149);
1171	// test_file!(xcsp3_ex_150);
1172	// test_file!(xcsp3_ex_151);
1173	// test_file!(xcsp3_ex_152);
1174	// test_file!(xcsp3_ex_153);
1175	// test_file!(xcsp3_ex_154);
1176	// test_file!(xcsp3_ex_155);
1177	// test_file!(xcsp3_ex_156);
1178	// test_file!(xcsp3_ex_157);
1179	// test_file!(xcsp3_ex_158);
1180	// test_file!(xcsp3_ex_159);
1181	// test_file!(xcsp3_ex_160);
1182	// test_file!(xcsp3_ex_161);
1183	// test_file!(xcsp3_ex_162);
1184	// test_file!(xcsp3_ex_163);
1185	// test_file!(xcsp3_ex_164);
1186	// test_file!(xcsp3_ex_165);
1187	// test_file!(xcsp3_ex_166);
1188	test_file!(xcsp3_ex_167);
1189	// test_file!(xcsp3_ex_168);
1190	// test_file!(xcsp3_ex_169);
1191	// test_file!(xcsp3_ex_170);
1192	// test_file!(xcsp3_ex_171);
1193	// test_file!(xcsp3_ex_172);
1194	// test_file!(xcsp3_ex_173);
1195	// test_file!(xcsp3_ex_174);
1196	// test_file!(xcsp3_ex_175);
1197	// test_file!(xcsp3_ex_176);
1198	// test_file!(xcsp3_ex_177);
1199	// test_file!(xcsp3_ex_178);
1200	// test_file!(xcsp3_ex_179);
1201	// test_file!(xcsp3_ex_180);
1202	// test_file!(xcsp3_ex_181);
1203	// test_file!(xcsp3_ex_182);
1204	// test_file!(xcsp3_ex_183);
1205	// test_file!(xcsp3_ex_184);
1206	// test_file!(xcsp3_ex_185);
1207	// test_file!(xcsp3_ex_186);
1208	// test_file!(xcsp3_ex_187);
1209	// test_file!(xcsp3_ex_188);
1210	// test_file!(xcsp3_ex_189);
1211	// test_file!(xcsp3_ex_190);
1212	// test_file!(xcsp3_ex_191);
1213}