Skip to main content

flatzinc_serde/
error.rs

1//! Error types for FlatZinc parsing or deserialization.
2
3use std::{
4	error::Error,
5	fmt::{self, Display},
6	io,
7	str::Utf8Error,
8};
9
10#[cfg(feature = "fzn")]
11use winnow::error::{ContextError, ParseError};
12
13#[cfg(feature = "fzn")]
14use crate::fzn::Stream;
15
16/// Errors that can occur when parsing `.fzn` models.
17#[derive(Debug)]
18pub enum FznParseError {
19	/// Error reading from the source.
20	Io(io::Error),
21	/// Error converting to utf8.
22	Utf8Error(Utf8Error),
23	/// Missing solve item in the model.
24	MissingSolveItem,
25	/// Multiple solve items were encountered in the model.
26	MultipleSolveItems,
27	/// An error in the syntax of the `fzn`.
28	SyntaxError(String),
29	/// An error when linking the variables and arrays in the model.
30	LinkError(LinkError),
31}
32
33/// Error produced while linking an variable and array references of the model.
34#[derive(Clone, PartialEq, Eq, Debug)]
35pub enum LinkError {
36	/// A predicate or annotation identifier could not be interned.
37	IdentifierError {
38		/// The identifier string that failed to intern.
39		ident: String,
40		/// The interner error message.
41		err: String,
42	},
43	/// A named literal could not be resolved to a variable or array.
44	UnknownReference(String),
45	/// A named array identifier that was used as a literal.
46	NestedArray(String),
47	/// Duplicate definition of a name.
48	DuplicateDefinition(String),
49}
50
51impl Display for FznParseError {
52	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
53		match self {
54			Self::Io(error) => write!(f, "error reading from source: {error}"),
55			Self::Utf8Error(error) => write!(f, "invalid utf8: {error}"),
56			Self::MissingSolveItem => write!(f, "missing solve item"),
57			Self::MultipleSolveItems => write!(f, "multiple solve items"),
58			Self::SyntaxError(error) => write!(f, "syntax error: {error}"),
59			Self::LinkError(error) => {
60				write!(f, "error linking model: {error}")
61			}
62		}
63	}
64}
65
66impl Error for FznParseError {}
67
68impl From<LinkError> for FznParseError {
69	fn from(error: LinkError) -> Self {
70		Self::LinkError(error)
71	}
72}
73
74#[cfg(feature = "fzn")]
75impl<Identifier, F> From<ParseError<Stream<'_, Identifier, F>, ContextError>> for FznParseError {
76	fn from(value: ParseError<Stream<'_, Identifier, F>, ContextError>) -> Self {
77		Self::SyntaxError(value.to_string())
78	}
79}
80
81impl From<Utf8Error> for FznParseError {
82	fn from(value: Utf8Error) -> Self {
83		Self::Utf8Error(value)
84	}
85}
86
87impl From<io::Error> for FznParseError {
88	fn from(value: io::Error) -> Self {
89		Self::Io(value)
90	}
91}
92
93impl Display for LinkError {
94	/// Format a linker error for parser and deserializer diagnostics.
95	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96		match self {
97			Self::IdentifierError { ident, err } => {
98				write!(f, "failed to intern identifier `{ident}`: {err}")
99			}
100			Self::UnknownReference(name) => {
101				write!(f, "unknown FlatZinc variable or array `{name}`")
102			}
103			Self::NestedArray(name) => {
104				write!(f, "array identifier `{name}` used as part of an array")
105			}
106			Self::DuplicateDefinition(name) => {
107				write!(f, "duplicate definition of `{name}`")
108			}
109		}
110	}
111}
112
113impl Error for LinkError {}