Skip to main content

egml_core/
error.rs

1use crate::model::base::Id;
2use thiserror::Error;
3
4/// Errors returned by `egml-core` operations.
5#[derive(Error, Debug, Eq, PartialEq, Hash, Clone)]
6pub enum Error {
7    /// Returned when a floating-point coordinate is not finite (NaN or ±infinity).
8    ///
9    /// The inner string names the offending coordinate component: `"x"`, `"y"`, or `"z"`.
10    /// GML requires all coordinate values in a `DirectPosition` to be real numbers
11    /// (ISO 19136 §9.4 `DirectPositionType`).
12    #[error(
13        "coordinate '{0}' has a non-finite value (NaN or ±infinity); all GML coordinate values must be real numbers (ISO 19136 §9.4)"
14    )]
15    NonFiniteCoordinate(&'static str),
16
17    /// Returned when a collection has fewer elements than the minimum required by
18    /// the GML geometry constraint.
19    ///
20    /// The inner string is a human-readable description of the violated constraint,
21    /// e.g. `"LinearRing requires at least 3 positions (ISO 19136 §10.5.12)"`.
22    #[error(
23        "{geometry} requires at least {minimum} elements ({spec:?}) [id={id:?}] [message={message:?}]"
24    )]
25    TooFewElements {
26        geometry: &'static str,
27        minimum: usize,
28        spec: Option<&'static str>,
29        id: Option<Id>,
30        message: Option<String>,
31    },
32
33    /// Returned when a collection contains a number of elements that is not
34    /// accepted by the operation (e.g. a `Triangle` not given exactly 3 points).
35    ///
36    /// The inner string describes which collection or argument was invalid.
37    #[error("invalid number of elements: {0}")]
38    WrongElementCount(&'static str),
39
40    /// Returned when an operation requires a non-empty input but received an empty one.
41    ///
42    /// The inner string names the offending parameter or context (e.g. `"solid"`,
43    /// `"multi curve"`).
44    #[error("'{0}' must not be empty")]
45    EmptyCollection(&'static str),
46
47    /// Returned when a geometry contains two identical positions where all positions
48    /// must be distinct (e.g. all three vertices of a [`Triangle`](crate::model::geometry::primitives::Triangle)
49    /// must be different, per ISO 19136 §10.5.9).
50    #[error(
51        "geometry contains two identical positions; all positions must be distinct (ISO 19136 §10.5.9)"
52    )]
53    IdenticalPositions,
54
55    /// Returned when adjacent positions in a sequence are equal and the geometry type
56    /// requires all consecutive positions to differ.
57    ///
58    /// Applies to [`LinearRing`](crate::model::geometry::primitives::LinearRing)
59    /// (ISO 19136 §10.5.12) and [`LineString`](crate::model::geometry::primitives::LineString)
60    /// (ISO 19136 §10.4.4).
61    #[error(
62        "sequence contains adjacent duplicate positions; consecutive coordinates must be distinct (ISO 19136 §10.4.3)"
63    )]
64    AdjacentDuplicatePositions,
65
66    /// Returned when the first and last position of a ring are equal.
67    ///
68    /// A `gml:LinearRing` is implicitly closed: the geometry engine connects the
69    /// last position back to the first automatically.  An explicit repeated closing
70    /// vertex is therefore redundant and invalid (ISO 19136 §10.5.12).
71    #[error(
72        "linear ring has matching first and last positions; gml:LinearRing is implicitly closed and must not include an explicit closing vertex (ISO 19136 §10.5.12)"
73    )]
74    RepeatedClosingVertex,
75
76    /// Returned when an [`Envelope`](crate::model::geometry::Envelope) is constructed
77    /// with a lower corner that is strictly greater than the upper corner in one or
78    /// more coordinate components.
79    ///
80    /// The inner string names the offending component (`"x"`, `"y"`, or `"z"`).
81    /// ISO 19136 §10.1.4 requires `lowerCorner ≤ upperCorner` in every component.
82    #[error(
83        "envelope lowerCorner.{0} exceeds upperCorner.{0}; each component of lowerCorner must be ≤ the corresponding upperCorner component (ISO 19136 §10.1.4)"
84    )]
85    InvalidEnvelopeBounds(&'static str),
86
87    /// Returned when the earcut polygon triangulation algorithm produces no triangles.
88    ///
89    /// The inner string provides additional context about the failure (e.g. which
90    /// polygon or patch could not be decomposed).
91    #[error("polygon triangulation (earcut) failed: {0}")]
92    TriangulationFailed(&'static str),
93}