Skip to main content

panproto_lens/
error.rs

1//! Error types for lens operations.
2//!
3//! [`LensError`] covers failures during lens construction and combinator
4//! compilation. [`LawViolation`] reports failures of the round-trip laws
5//! (`GetPut` and `PutGet`).
6
7use std::fmt;
8
9/// Errors from lens construction, combinator compilation, or lens operations.
10#[derive(Debug, thiserror::Error)]
11#[non_exhaustive]
12pub enum LensError {
13    /// A schema vertex referenced by a combinator was not found.
14    #[error("vertex not found: {0}")]
15    VertexNotFound(String),
16
17    /// An edge referenced by a combinator was not found.
18    #[error("edge not found: {src} -> {tgt}")]
19    EdgeNotFound {
20        /// Source vertex.
21        src: String,
22        /// Target vertex.
23        tgt: String,
24    },
25
26    /// A combinator references an invalid field name.
27    #[error("field not found: {0}")]
28    FieldNotFound(String),
29
30    /// A combinator references an NSID on a vertex that has no NSID.
31    #[error("no NSID on vertex: {0}")]
32    NsidNotFound(String),
33
34    /// A combinator references a constraint sort that does not exist.
35    #[error("constraint sort not found: {0}")]
36    ConstraintSortNotFound(String),
37
38    /// A combinator references an edge kind that does not exist.
39    #[error("edge kind not found: {0}")]
40    EdgeKindNotFound(String),
41
42    /// Type coercion between incompatible kinds.
43    #[error("cannot coerce from {from} to {to}")]
44    IncompatibleCoercion {
45        /// Source kind.
46        from: String,
47        /// Target kind.
48        to: String,
49    },
50
51    /// Lens composition failed because schemas don't align.
52    #[error(
53        "composition failed: target schema of first lens does not match source schema of second"
54    )]
55    CompositionMismatch,
56
57    /// Delegation to the restrict pipeline failed.
58    #[error("restrict error: {0}")]
59    Restrict(#[from] panproto_inst::RestrictError),
60
61    /// A complement was incompatible with the view during `put`.
62    #[error("complement mismatch: {detail}")]
63    ComplementMismatch {
64        /// Details about the mismatch.
65        detail: String,
66    },
67
68    /// A protolens operation failed.
69    #[error("protolens error: {0}")]
70    ProtolensError(String),
71
72    /// An edit could not be applied during law checking.
73    #[error("edit apply error: {0}")]
74    EditApply(#[from] panproto_inst::EditError),
75
76    /// Partial-monoid `Complement::compose` rejected an attempted merge
77    /// because both operands carried distinct entries on the same key.
78    /// Composition is defined exactly when the two complements agree on
79    /// every shared key (idempotent merge); disagreement is the
80    /// boundary of the partial-monoid's domain of definition.
81    #[error("complement conflict on {kind} key `{key}`")]
82    ComplementConflict {
83        /// Which keyed map produced the conflict.
84        kind: &'static str,
85        /// String representation of the conflicting key.
86        key: String,
87    },
88
89    /// Partial-monoid `Complement::compose` rejected an attempted merge
90    /// because the two complements were taken at distinct source
91    /// schemas (their fingerprints differ).
92    #[error(
93        "complement fingerprint mismatch: {left:#x} vs {right:#x}; complements were captured against different source schemas"
94    )]
95    ComplementFingerprintMismatch {
96        /// Left fingerprint.
97        left: u64,
98        /// Right fingerprint.
99        right: u64,
100    },
101
102    /// No enrichment synthesis driver is registered for the named
103    /// `(kind, enricher)` pair. The driver must be registered via
104    /// [`enrichment_registry::register_enricher`](crate::enrichment_registry::register_enricher)
105    /// before a protolens that adds this enrichment can be
106    /// instantiated.
107    #[error("no enrichment driver registered for ({kind:?}, {enricher:?})")]
108    UnknownEnricher {
109        /// The enrichment kind requested.
110        kind: panproto_gat::EnrichmentKind,
111        /// The enricher name (e.g. a grammar name for `Layout`).
112        enricher: String,
113    },
114
115    /// The registered enrichment synthesis driver rejected its input.
116    #[error("enrichment synthesis failed ({kind:?}, {enricher}): {detail}")]
117    EnrichmentSynthesisFailed {
118        /// The enrichment kind.
119        kind: panproto_gat::EnrichmentKind,
120        /// The enricher name.
121        enricher: String,
122        /// Human-readable failure.
123        detail: String,
124    },
125}
126
127/// A violation of a round-trip lens law.
128#[derive(Debug)]
129#[non_exhaustive]
130pub enum LawViolation {
131    /// `GetPut` law violation: `put(s, get(s)) != s`.
132    GetPut {
133        /// Human-readable description of the difference.
134        detail: String,
135    },
136
137    /// `PutGet` law violation: `get(put(s, v)) != v`.
138    PutGet {
139        /// Human-readable description of the difference.
140        detail: String,
141    },
142
143    /// An error occurred while checking the laws.
144    Error(LensError),
145}
146
147impl fmt::Display for LawViolation {
148    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
149        match self {
150            Self::GetPut { detail } => write!(f, "GetPut law violated: {detail}"),
151            Self::PutGet { detail } => write!(f, "PutGet law violated: {detail}"),
152            Self::Error(e) => write!(f, "error during law check: {e}"),
153        }
154    }
155}
156
157impl std::error::Error for LawViolation {
158    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
159        match self {
160            Self::Error(e) => Some(e),
161            _ => None,
162        }
163    }
164}