Skip to main content

mesh_sieve/
mesh_error.rs

1//! MeshSieveError: Unified error type for mesh-sieve public APIs
2//!
3//! This error type is used throughout the mesh-sieve library to provide robust,
4//! non-panicking error handling for all public APIs.
5
6use std::fmt::Debug;
7use thiserror::Error;
8
9/// Unified error type for mesh-sieve operations.
10#[derive(Debug, Error)]
11pub enum MeshSieveError {
12    /// Error indicating that the overlap graph is missing required neighbor links.
13    #[error("Missing overlap: {source}")]
14    MissingOverlap {
15        source: Box<dyn std::error::Error + Send + Sync>,
16    },
17    /// Generic mesh error (for internal use, e.g. error propagation)
18    #[error("mesh error: {0}")]
19    MeshError(Box<MeshSieveError>),
20    /// Renumbering permutation was invalid.
21    #[error("Invalid renumbering permutation: {0}")]
22    InvalidPermutation(String),
23    /// GPU buffer mapping failed.
24    #[error("GPU buffer mapping failed")]
25    GpuMappingFailed,
26    /// Attempted to construct a PointId with a zero value (invalid).
27    #[error("PointId must be non-zero (0 is reserved as invalid/sentinel)")]
28    InvalidPointId,
29    /// Vertical arrow references a point missing from the base or cap sieve.
30    #[error("stack arrow references missing point in {role}: {point}")]
31    StackMissingPoint { role: &'static str, point: String },
32    /// Mutation on a read-only stack (e.g., `ComposedStack`) is not allowed.
33    #[error("Unsupported stack operation: {0}")]
34    UnsupportedStackOperation(&'static str),
35    /// A point appeared in a cone but wasn’t in the initial point set.
36    #[error("Topology error: point `{0}` found in cone but not in point set")]
37    MissingPointInCone(String),
38    /// Attempted to access a point that is not present in the CSR chart.
39    #[error("Topology error: point `{0}` not present in chart")]
40    UnknownPoint(String),
41    /// The mesh topology contains a cycle; expected a DAG.
42    #[error("Topology error: cycle detected in mesh (expected DAG)")]
43    CycleDetected,
44    /// Attempt to insert a zero-length slice, which is invalid.
45    #[error("Atlas error: zero-length slice is not allowed")]
46    ZeroLengthSlice,
47    /// Attempt to insert a point that’s already in the atlas.
48    #[error("Atlas error: point {0:?} already present")]
49    DuplicatePoint(crate::topology::point::PointId),
50    /// Internal invariant broken: point in order but missing from map.
51    #[error("Atlas internal error: missing length for point {0:?}")]
52    MissingAtlasPoint(crate::topology::point::PointId),
53    /// Attempt to access data for a point not in the atlas.
54    #[error("Section error: point {0:?} not found in atlas")]
55    PointNotInAtlas(crate::topology::point::PointId),
56    /// Attempt to access a point not in the atlas.
57    #[error("SievedArray error: point {0:?} not found in atlas")]
58    SievedArrayPointNotInAtlas(crate::topology::point::PointId),
59
60    /// Mismatch between expected and provided slice length for a point.
61    #[error("Section error: slice length mismatch for {point:?}: expected {expected}, got {found}")]
62    SliceLengthMismatch {
63        point: crate::topology::point::PointId,
64        expected: usize,
65        found: usize,
66    },
67    /// Slice length changed for a point during atlas mutation.
68    #[deprecated(note = "Use AtlasPointLengthChanged")]
69    #[error("atlas slice length changed for {point:?}: {old} -> {new}")]
70    AtlasSliceLengthChanged {
71        point: crate::topology::point::PointId,
72        old: usize,
73        new: usize,
74    },
75    /// Mismatch between expected and provided slice length for a point (SievedArray).
76    #[error(
77        "SievedArray error: slice length mismatch at {point:?}: expected {expected}, got {found}"
78    )]
79    SievedArraySliceLengthMismatch {
80        point: crate::topology::point::PointId,
81        expected: usize,
82        found: usize,
83    },
84
85    /// Refinement attempted to map multiple coarse points into the same fine point.
86    #[error("Refinement maps more than one coarse point into the same fine point {fine:?}")]
87    DuplicateRefinementTarget {
88        fine: crate::topology::point::PointId,
89    },
90
91    /// Attempt to add a point to the section failed at atlas insertion.
92    #[error("Section error: failed to add point {0:?} to atlas: {1}")]
93    AtlasInsertionFailed(
94        crate::topology::point::PointId,
95        #[source] Box<MeshSieveError>,
96    ),
97    /// Attempt to remove or copy data for a point that disappeared.
98    #[error("Section internal error: missing data for point {0:?}")]
99    MissingSectionPoint(crate::topology::point::PointId),
100    /// Bulk scatter mismatch between total lengths.
101    #[error("scatter total length mismatch (expected={expected}, found={found})")]
102    ScatterLengthMismatch { expected: usize, found: usize },
103    /// One of the scatter chunks did not fit.
104    #[error("scatter chunk out of bounds or overflow (offset={offset}, len={len})")]
105    ScatterChunkMismatch { offset: usize, len: usize },
106    /// Attempted to use a scatter plan built from an outdated atlas.
107    #[error("plan stale: built for atlas version {expected}, current {found}")]
108    AtlasPlanStale { expected: u64, found: u64 },
109    /// Missing section name in a multi/mixed scatter operation.
110    #[error("Missing section name {name}")]
111    MissingSectionName { name: String },
112    /// A DM vector is associated with a different section than the requested operation.
113    #[error("vector section mismatch: expected {expected}, found {found:?}")]
114    VectorSectionMismatch {
115        expected: String,
116        found: Option<String>,
117    },
118    /// Tagged section buffer type mismatch.
119    #[error("Tagged section type mismatch (expected {expected:?}, found {found:?})")]
120    TaggedSectionTypeMismatch {
121        expected: crate::data::mixed_section::ScalarType,
122        found: crate::data::mixed_section::ScalarType,
123    },
124    /// Missing ownership metadata for a point.
125    #[error("Ownership missing for point {0:?}")]
126    MissingOwnership(crate::topology::point::PointId),
127    /// Point's slice length changed across atlas rebuild.
128    #[error("atlas point length changed for {point:?} (expected={expected}, found={found})")]
129    AtlasPointLengthChanged {
130        point: crate::topology::point::PointId,
131        expected: usize,
132        found: usize,
133    },
134    /// Reducer or path length mismatch when no concrete point exists.
135    #[error("reduction length mismatch (expected={expected}, found={found})")]
136    ReducerLengthMismatch { expected: usize, found: usize },
137    /// Atlas slices are not contiguous as expected.
138    #[error(
139        "atlas contiguity mismatch for {point:?} (expected_offset={expected}, found_offset={found})"
140    )]
141    AtlasContiguityMismatch {
142        point: crate::topology::point::PointId,
143        expected: usize,
144        found: usize,
145    },
146    /// Failure converting count to primitive (should never happen if FromPrimitive is well-behaved).
147    #[error("SievedArray error: cannot convert count {0} via FromPrimitive")]
148    SievedArrayPrimitiveConversionFailure(usize),
149    /// Delta application failed because source and dest slices had different lengths.
150    #[error("Delta error: slice length mismatch (src.len={expected}, dest.len={found})")]
151    DeltaLengthMismatch { expected: usize, found: usize },
152    /// Constraint index is out of bounds for a point slice.
153    #[error("Constraint error at point {point:?}: DOF index {index} out of bounds (len={len})")]
154    ConstraintIndexOutOfBounds {
155        point: crate::topology::point::PointId,
156        index: usize,
157        len: usize,
158    },
159    /// Refinement template did not match the cell cone size.
160    #[error(
161        "Refinement topology mismatch for cell {cell:?}: template {template} expects {expected} vertices, found {found}"
162    )]
163    RefinementTopologyMismatch {
164        cell: crate::topology::point::PointId,
165        template: &'static str,
166        expected: usize,
167        found: usize,
168    },
169    /// Unsupported cell type encountered during refinement.
170    #[error("Unsupported refinement cell type {cell_type:?} at cell {cell:?}")]
171    UnsupportedRefinementCellType {
172        cell: crate::topology::point::PointId,
173        cell_type: crate::topology::cell_type::CellType,
174    },
175    /// Partition‐point computation overflowed to zero (invalid owner).
176    #[error("Invalid partition owner: computed raw ID = 0")]
177    PartitionPointOverflow,
178    /// The `parts` slice is missing an entry for point `{0}`.
179    #[error("No partition mapping for point ID {0}")]
180    PartitionIndexOutOfBounds(usize),
181    /// Error sending or receiving data over the wire.
182    #[error("communication error: {0}")]
183    Communication(#[from] CommError),
184
185    /// Missing expected recv count for a neighbor during data exchange.
186    #[error("Missing recv count for neighbor {neighbor}")]
187    MissingRecvCount { neighbor: usize },
188    /// Error accessing a section for a given point.
189    #[error("Section access error at point {point:?}: {source}")]
190    SectionAccess {
191        point: crate::topology::point::PointId,
192        #[source]
193        source: Box<dyn std::error::Error + Send + Sync>,
194    },
195    /// Communication error for a specific neighbor.
196    #[error("Communication error with neighbor {neighbor}: {source}")]
197    CommError {
198        neighbor: usize,
199        #[source]
200        source: Box<dyn std::error::Error + Send + Sync>,
201    },
202    /// Buffer size mismatch during data exchange.
203    #[error("Buffer size mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
204    BufferSizeMismatch {
205        neighbor: usize,
206        expected: usize,
207        got: usize,
208    },
209    /// Part count mismatch during data exchange.
210    #[error("Part count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
211    PartCountMismatch {
212        neighbor: usize,
213        expected: usize,
214        got: usize,
215    },
216    /// Lengths array count mismatch during data exchange.
217    #[error("Lengths count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
218    LengthsCountMismatch {
219        neighbor: usize,
220        expected: usize,
221        got: usize,
222    },
223    /// Payload element count mismatch during data exchange.
224    #[error("Payload count mismatch for neighbor {neighbor}: expected {expected}, got {got}")]
225    PayloadCountMismatch {
226        neighbor: usize,
227        expected: usize,
228        got: usize,
229    },
230
231    #[error("Overlap link not found for (local={0}, rank={1})")]
232    OverlapLinkMissing(crate::topology::point::PointId, usize),
233
234    #[error("Overlap: edge must be Local->Part, found {src:?} -> {dst:?}")]
235    OverlapNonBipartite {
236        src: crate::overlap::overlap::OvlId,
237        dst: crate::overlap::overlap::OvlId,
238    },
239    #[error("expected Local(_), found {found:?}")]
240    OverlapExpectedLocal {
241        found: crate::overlap::overlap::OvlId,
242    },
243    #[error("expected Part(_), found {found:?}")]
244    OverlapExpectedPart {
245        found: crate::overlap::overlap::OvlId,
246    },
247
248    /// Generic I/O error for mesh readers/writers.
249    #[error("I/O error: {0}")]
250    Io(#[from] std::io::Error),
251    /// HDF5 error for mesh readers/writers.
252    #[error("HDF5 error: {0}")]
253    Hdf5(#[from] hdf5::Error),
254    /// Invalid or inverted geometry detected.
255    #[error("Geometry error: {0}")]
256    InvalidGeometry(String),
257    /// Parse error while reading mesh formats.
258    #[error("Mesh I/O parse error: {0}")]
259    MeshIoParse(String),
260    /// Duplicate arrow detected in topology.
261    #[error("Topology error: duplicate arrow {src:?} -> {dst:?}")]
262    DuplicateArrow {
263        src: crate::topology::point::PointId,
264        dst: crate::topology::point::PointId,
265    },
266    /// Cell cone size did not match the expected number of vertices.
267    #[error(
268        "Topology error: cell {cell:?} of type {cell_type:?} expects cone size {expected}, found {found}"
269    )]
270    ConeSizeMismatch {
271        cell: crate::topology::point::PointId,
272        cell_type: crate::topology::cell_type::CellType,
273        expected: usize,
274        found: usize,
275    },
276    /// Closure vertex count did not match the expected number of vertices.
277    #[error(
278        "Topology error: cell {cell:?} of type {cell_type:?} expects {expected} vertices in closure, found {found}"
279    )]
280    ClosureVertexCountMismatch {
281        cell: crate::topology::point::PointId,
282        cell_type: crate::topology::cell_type::CellType,
283        expected: usize,
284        found: usize,
285    },
286    /// Non-manifold entity detected by counting incident cells.
287    #[error(
288        "Topology error: non-manifold entity {point:?} (dim={dimension}) has {incident_cells} incident cells"
289    )]
290    NonManifoldIncidentCells {
291        point: crate::topology::point::PointId,
292        dimension: u32,
293        incident_cells: usize,
294    },
295    #[error("Overlap: payload.rank {found} != Part({expected})")]
296    OverlapRankMismatch { expected: usize, found: usize },
297    /// Periodic mapping for a slave point conflicted with existing entry.
298    #[error(
299        "Periodic mapping conflict for slave {slave:?}: existing master {existing:?}, new master {new:?}"
300    )]
301    PeriodicMappingConflict {
302        slave: crate::topology::point::PointId,
303        existing: crate::topology::point::PointId,
304        new: crate::topology::point::PointId,
305    },
306    #[error("Overlap: Part node found in base_points()")]
307    OverlapPartInBasePoints,
308    #[error("Overlap: Local node found in cap_points()")]
309    OverlapLocalInCapPoints,
310    #[error("Overlap: duplicate edge {src:?} -> {dst:?}")]
311    OverlapDuplicateEdge {
312        src: crate::overlap::overlap::OvlId,
313        dst: crate::overlap::overlap::OvlId,
314    },
315    #[error("Overlap: empty Part({rank}) node (no incoming edges)")]
316    OverlapEmptyPart { rank: usize },
317
318    /// Local topology contains a point without ownership metadata.
319    #[error("Topology point {point:?} missing ownership metadata")]
320    TopologyPointMissingOwnership {
321        point: crate::topology::point::PointId,
322    },
323    /// Ownership metadata references a point missing from the local topology.
324    #[error("Ownership entry for point {point:?} missing from local topology")]
325    OwnershipPointMissingTopology {
326        point: crate::topology::point::PointId,
327    },
328    /// Ownership ghost flag conflicts with the owning rank.
329    #[error("Ownership ghost flag mismatch for point {point:?}: owner={owner}, my_rank={my_rank}")]
330    OwnershipGhostMismatch {
331        point: crate::topology::point::PointId,
332        owner: usize,
333        my_rank: usize,
334    },
335    /// Ghost point is missing a required overlap link to its owning rank.
336    #[error("Ghost point {point:?} owned by rank {owner} missing overlap link")]
337    GhostPointMissingOverlapLink {
338        point: crate::topology::point::PointId,
339        owner: usize,
340    },
341    /// Overlap references a point absent from the local topology.
342    #[error("Overlap link references point {point:?} missing from local topology")]
343    OverlapPointMissingTopology {
344        point: crate::topology::point::PointId,
345    },
346    /// Overlap references a point missing ownership metadata.
347    #[error("Overlap link references point {point:?} missing ownership metadata")]
348    OverlapPointMissingOwnership {
349        point: crate::topology::point::PointId,
350    },
351
352    /// Out edge exists but its mirrored in edge is missing.
353    #[error("overlap in/out mirror missing: {src:?} -> {dst:?}")]
354    OverlapInOutMirrorMissing {
355        src: crate::overlap::overlap::OvlId,
356        dst: crate::overlap::overlap::OvlId,
357    },
358
359    /// Out/in edges exist but payloads differ (rank/remote_point mismatch).
360    #[error("overlap in/out payload mismatch on {src:?} -> {dst:?}: out={out:?} in={inn:?}")]
361    OverlapInOutPayloadMismatch {
362        src: crate::overlap::overlap::OvlId,
363        dst: crate::overlap::overlap::OvlId,
364        out: crate::overlap::overlap::Remote,
365        inn: crate::overlap::overlap::Remote,
366    },
367
368    /// Counts of edges in out vs. in adjacency differ.
369    #[error("overlap in/out edge count mismatch: out={out_edges}, in={in_edges}")]
370    OverlapInOutEdgeCountMismatch { out_edges: usize, in_edges: usize },
371
372    #[error(
373        "Overlap resolution conflict for (local={local}, rank={rank}): existing={existing:?}, new={new:?}"
374    )]
375    OverlapResolutionConflict {
376        local: crate::topology::point::PointId,
377        rank: usize,
378        existing: Option<crate::topology::point::PointId>,
379        new: crate::topology::point::PointId,
380    },
381}
382
383impl PartialEq for MeshSieveError {
384    fn eq(&self, other: &MeshSieveError) -> bool {
385        use MeshSieveError::*;
386        match (self, other) {
387            (InvalidPointId, InvalidPointId)
388            | (CycleDetected, CycleDetected)
389            | (ZeroLengthSlice, ZeroLengthSlice)
390            | (PartitionPointOverflow, PartitionPointOverflow)
391            | (GpuMappingFailed, GpuMappingFailed) => true,
392            (InvalidGeometry(a), InvalidGeometry(b)) => a == b,
393            (DuplicateArrow { src: s1, dst: d1 }, DuplicateArrow { src: s2, dst: d2 }) => {
394                s1 == s2 && d1 == d2
395            }
396            (
397                ConeSizeMismatch {
398                    cell: c1,
399                    cell_type: t1,
400                    expected: e1,
401                    found: f1,
402                },
403                ConeSizeMismatch {
404                    cell: c2,
405                    cell_type: t2,
406                    expected: e2,
407                    found: f2,
408                },
409            ) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
410            (
411                ClosureVertexCountMismatch {
412                    cell: c1,
413                    cell_type: t1,
414                    expected: e1,
415                    found: f1,
416                },
417                ClosureVertexCountMismatch {
418                    cell: c2,
419                    cell_type: t2,
420                    expected: e2,
421                    found: f2,
422                },
423            ) => c1 == c2 && t1 == t2 && e1 == e2 && f1 == f2,
424            (
425                NonManifoldIncidentCells {
426                    point: p1,
427                    dimension: d1,
428                    incident_cells: c1,
429                },
430                NonManifoldIncidentCells {
431                    point: p2,
432                    dimension: d2,
433                    incident_cells: c2,
434                },
435            ) => p1 == p2 && d1 == d2 && c1 == c2,
436            (UnsupportedStackOperation(a), UnsupportedStackOperation(b)) => a == b,
437            (
438                VectorSectionMismatch {
439                    expected: e1,
440                    found: f1,
441                },
442                VectorSectionMismatch {
443                    expected: e2,
444                    found: f2,
445                },
446            ) => e1 == e2 && f1 == f2,
447            (MissingPointInCone(a), MissingPointInCone(b)) => a == b,
448            (UnknownPoint(a), UnknownPoint(b)) => a == b,
449            (DuplicatePoint(a), DuplicatePoint(b)) => a == b,
450            (MissingAtlasPoint(a), MissingAtlasPoint(b)) => a == b,
451            (PointNotInAtlas(a), PointNotInAtlas(b)) => a == b,
452            (SievedArrayPointNotInAtlas(a), SievedArrayPointNotInAtlas(b)) => a == b,
453            (
454                SliceLengthMismatch {
455                    point: p1,
456                    expected: e1,
457                    found: f1,
458                },
459                SliceLengthMismatch {
460                    point: p2,
461                    expected: e2,
462                    found: f2,
463                },
464            ) => p1 == p2 && e1 == e2 && f1 == f2,
465            (
466                AtlasSliceLengthChanged {
467                    point: p1,
468                    old: o1,
469                    new: n1,
470                },
471                AtlasSliceLengthChanged {
472                    point: p2,
473                    old: o2,
474                    new: n2,
475                },
476            ) => p1 == p2 && o1 == o2 && n1 == n2,
477            (
478                AtlasPointLengthChanged {
479                    point: p1,
480                    expected: e1,
481                    found: f1,
482                },
483                AtlasPointLengthChanged {
484                    point: p2,
485                    expected: e2,
486                    found: f2,
487                },
488            ) => p1 == p2 && e1 == e2 && f1 == f2,
489            (
490                SievedArraySliceLengthMismatch {
491                    point: p1,
492                    expected: e1,
493                    found: f1,
494                },
495                SievedArraySliceLengthMismatch {
496                    point: p2,
497                    expected: e2,
498                    found: f2,
499                },
500            ) => p1 == p2 && e1 == e2 && f1 == f2,
501            (DuplicateRefinementTarget { fine: f1 }, DuplicateRefinementTarget { fine: f2 }) => {
502                f1 == f2
503            }
504            (AtlasInsertionFailed(p1, _), AtlasInsertionFailed(p2, _)) => p1 == p2,
505            (MissingSectionPoint(a), MissingSectionPoint(b)) => a == b,
506            (
507                ScatterLengthMismatch {
508                    expected: e1,
509                    found: f1,
510                },
511                ScatterLengthMismatch {
512                    expected: e2,
513                    found: f2,
514                },
515            ) => e1 == e2 && f1 == f2,
516            (
517                ReducerLengthMismatch {
518                    expected: e1,
519                    found: f1,
520                },
521                ReducerLengthMismatch {
522                    expected: e2,
523                    found: f2,
524                },
525            ) => e1 == e2 && f1 == f2,
526            (
527                ScatterChunkMismatch {
528                    offset: o1,
529                    len: l1,
530                },
531                ScatterChunkMismatch {
532                    offset: o2,
533                    len: l2,
534                },
535            ) => o1 == o2 && l1 == l2,
536            (
537                AtlasContiguityMismatch {
538                    point: p1,
539                    expected: e1,
540                    found: f1,
541                },
542                AtlasContiguityMismatch {
543                    point: p2,
544                    expected: e2,
545                    found: f2,
546                },
547            ) => p1 == p2 && e1 == e2 && f1 == f2,
548            (
549                AtlasPlanStale {
550                    expected: e1,
551                    found: f1,
552                },
553                AtlasPlanStale {
554                    expected: e2,
555                    found: f2,
556                },
557            ) => e1 == e2 && f1 == f2,
558            (MissingSectionName { name: n1 }, MissingSectionName { name: n2 }) => n1 == n2,
559            (
560                TaggedSectionTypeMismatch {
561                    expected: e1,
562                    found: f1,
563                },
564                TaggedSectionTypeMismatch {
565                    expected: e2,
566                    found: f2,
567                },
568            ) => e1 == e2 && f1 == f2,
569            (MissingOwnership(a), MissingOwnership(b)) => a == b,
570            (
571                SievedArrayPrimitiveConversionFailure(a),
572                SievedArrayPrimitiveConversionFailure(b),
573            ) => a == b,
574            (
575                DeltaLengthMismatch {
576                    expected: e1,
577                    found: f1,
578                },
579                DeltaLengthMismatch {
580                    expected: e2,
581                    found: f2,
582                },
583            ) => e1 == e2 && f1 == f2,
584            (PartitionIndexOutOfBounds(a), PartitionIndexOutOfBounds(b)) => a == b,
585            (MissingRecvCount { neighbor: n1 }, MissingRecvCount { neighbor: n2 }) => n1 == n2,
586            (SectionAccess { point: p1, .. }, SectionAccess { point: p2, .. }) => p1 == p2,
587            (CommError { neighbor: n1, .. }, CommError { neighbor: n2, .. }) => n1 == n2,
588            (
589                BufferSizeMismatch {
590                    neighbor: n1,
591                    expected: e1,
592                    got: g1,
593                },
594                BufferSizeMismatch {
595                    neighbor: n2,
596                    expected: e2,
597                    got: g2,
598                },
599            ) => n1 == n2 && e1 == e2 && g1 == g2,
600            (
601                PartCountMismatch {
602                    neighbor: n1,
603                    expected: e1,
604                    got: g1,
605                },
606                PartCountMismatch {
607                    neighbor: n2,
608                    expected: e2,
609                    got: g2,
610                },
611            ) => n1 == n2 && e1 == e2 && g1 == g2,
612            (
613                LengthsCountMismatch {
614                    neighbor: n1,
615                    expected: e1,
616                    got: g1,
617                },
618                LengthsCountMismatch {
619                    neighbor: n2,
620                    expected: e2,
621                    got: g2,
622                },
623            ) => n1 == n2 && e1 == e2 && g1 == g2,
624            (
625                PayloadCountMismatch {
626                    neighbor: n1,
627                    expected: e1,
628                    got: g1,
629                },
630                PayloadCountMismatch {
631                    neighbor: n2,
632                    expected: e2,
633                    got: g2,
634                },
635            ) => n1 == n2 && e1 == e2 && g1 == g2,
636            (Communication(a), Communication(b)) => a == b,
637            (OverlapLinkMissing(a1, b1), OverlapLinkMissing(a2, b2)) => a1 == a2 && b1 == b2,
638            (
639                OverlapNonBipartite { src: s1, dst: d1 },
640                OverlapNonBipartite { src: s2, dst: d2 },
641            ) => s1 == s2 && d1 == d2,
642            (OverlapExpectedLocal { found: f1 }, OverlapExpectedLocal { found: f2 }) => f1 == f2,
643            (OverlapExpectedPart { found: f1 }, OverlapExpectedPart { found: f2 }) => f1 == f2,
644            (
645                OverlapRankMismatch {
646                    expected: e1,
647                    found: f1,
648                },
649                OverlapRankMismatch {
650                    expected: e2,
651                    found: f2,
652                },
653            ) => e1 == e2 && f1 == f2,
654            (OverlapPartInBasePoints, OverlapPartInBasePoints) => true,
655            (OverlapLocalInCapPoints, OverlapLocalInCapPoints) => true,
656            (
657                OverlapDuplicateEdge { src: s1, dst: d1 },
658                OverlapDuplicateEdge { src: s2, dst: d2 },
659            ) => s1 == s2 && d1 == d2,
660            (OverlapEmptyPart { rank: r1 }, OverlapEmptyPart { rank: r2 }) => r1 == r2,
661            (
662                TopologyPointMissingOwnership { point: p1 },
663                TopologyPointMissingOwnership { point: p2 },
664            ) => p1 == p2,
665            (
666                OwnershipPointMissingTopology { point: p1 },
667                OwnershipPointMissingTopology { point: p2 },
668            ) => p1 == p2,
669            (
670                OwnershipGhostMismatch {
671                    point: p1,
672                    owner: o1,
673                    my_rank: m1,
674                },
675                OwnershipGhostMismatch {
676                    point: p2,
677                    owner: o2,
678                    my_rank: m2,
679                },
680            ) => p1 == p2 && o1 == o2 && m1 == m2,
681            (
682                GhostPointMissingOverlapLink {
683                    point: p1,
684                    owner: o1,
685                },
686                GhostPointMissingOverlapLink {
687                    point: p2,
688                    owner: o2,
689                },
690            ) => p1 == p2 && o1 == o2,
691            (
692                OverlapPointMissingTopology { point: p1 },
693                OverlapPointMissingTopology { point: p2 },
694            ) => p1 == p2,
695            (
696                OverlapPointMissingOwnership { point: p1 },
697                OverlapPointMissingOwnership { point: p2 },
698            ) => p1 == p2,
699            (
700                OverlapInOutMirrorMissing { src: s1, dst: d1 },
701                OverlapInOutMirrorMissing { src: s2, dst: d2 },
702            ) => s1 == s2 && d1 == d2,
703            (
704                OverlapInOutPayloadMismatch {
705                    src: s1,
706                    dst: d1,
707                    out: o1,
708                    inn: i1,
709                },
710                OverlapInOutPayloadMismatch {
711                    src: s2,
712                    dst: d2,
713                    out: o2,
714                    inn: i2,
715                },
716            ) => s1 == s2 && d1 == d2 && o1 == o2 && i1 == i2,
717            (
718                OverlapInOutEdgeCountMismatch {
719                    out_edges: o1,
720                    in_edges: i1,
721                },
722                OverlapInOutEdgeCountMismatch {
723                    out_edges: o2,
724                    in_edges: i2,
725                },
726            ) => o1 == o2 && i1 == i2,
727            (
728                OverlapResolutionConflict {
729                    local: l1,
730                    rank: r1,
731                    existing: ex1,
732                    new: n1,
733                },
734                OverlapResolutionConflict {
735                    local: l2,
736                    rank: r2,
737                    existing: ex2,
738                    new: n2,
739                },
740            ) => l1 == l2 && r1 == r2 && ex1 == ex2 && n1 == n2,
741            _ => false,
742        }
743    }
744}
745impl Eq for MeshSieveError {}
746
747/// Low-level communicator failure.
748#[derive(Debug, thiserror::Error, Clone)]
749#[error("{0}")]
750pub struct CommError(pub String);
751
752impl PartialEq for CommError {
753    fn eq(&self, other: &CommError) -> bool {
754        self.0 == other.0
755    }
756}
757impl Eq for CommError {}