git-ents.gitmain
⌘K
foforge
error.rs190 lines · 6.2 KB · rusthistorycomment on this file
1//! Parse-time and evaluation-time error types.
2//!
3//! [`ParseError`] is a *validation verdict on author input*: an effect
4//! definition carrying a trigger that fails to parse must be rejected
5//! before it is stored (`effect.validation`), so every variant explains
6//! what the author wrote wrong. [`EvalError`] is infrastructure — a
7//! store read failed mid-evaluation — and never a statement about the
8//! query's meaning.
9
10use gix_hash::ObjectId;
11
12/// Everything that makes a `CommitQuery` malformed (`query.grammar`,
13/// `query.rev`, `query.meta`).
14#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
15#[non_exhaustive]
16pub enum ParseError {
17 /// The input ended where a term was required.
18 #[error("unexpected end of query; expected a term")]
19 UnexpectedEnd,
20
21 /// An atom other than `rev`, `results`, or `meta` was named. The
22 /// grammar deliberately has no content, time, or external-event
23 /// atoms (`query.no-extensions`).
24 #[error(
25 "unknown atom {name:?}: the grammar has exactly rev(), results(), and meta() \
26 (query.no-extensions)"
27 )]
28 UnknownAtom {
29 /// The atom name as written.
30 name: String,
31 },
32
33 /// Structurally expected input was missing at `at` (byte offset).
34 #[error("expected {expected} at byte {at}")]
35 Expected {
36 /// What the parser needed.
37 expected: &'static str,
38 /// Byte offset into the query text.
39 at: usize,
40 },
41
42 /// A parenthesis never closed.
43 #[error("unbalanced parenthesis opened at byte {at}")]
44 Unbalanced {
45 /// Byte offset of the unmatched `(`.
46 at: usize,
47 },
48
49 /// The query parsed, but input remained.
50 #[error("trailing input after query: {rest:?}")]
51 Trailing {
52 /// The unconsumed tail.
53 rest: String,
54 },
55
56 /// `results()` was given a status outside the closed taxonomy.
57 #[error("results() status must be pass, fail, error, or any; got {got:?}")]
58 BadStatus {
59 /// The status as written.
60 got: String,
61 },
62
63 /// `results()` was given an effect name that is not a valid single
64 /// ref-path segment (`effect.definition`).
65 #[error("effect name {got:?} is not a valid ref-path segment")]
66 BadEffectName {
67 /// The effect name as written.
68 got: String,
69 },
70
71 /// `results(self, ...)` was written in a trigger. `self` is
72 /// notation substituted at evaluation time (`query.workset`), never
73 /// a keyword an author may write.
74 #[error(
75 "`self` is substituted at evaluation time (query.workset); it cannot be written \
76 in a trigger"
77 )]
78 SelfKeyword,
79
80 /// A `rev()` expression named a `refs/meta/*` pattern, which is
81 /// outside `rev()`'s domain by definition (`query.rev`).
82 #[error("rev() must not name a refs/meta/* pattern; got {pattern:?} (query.rev)")]
83 MetaInRev {
84 /// The offending pattern.
85 pattern: String,
86 },
87
88 /// A `meta()` glob does not start with `refs/meta/`, so it could
89 /// never match an author-written meta-ref.
90 #[error("meta() glob must start with refs/meta/; got {glob:?} (query.meta)")]
91 MetaGlobOutside {
92 /// The glob as written.
93 glob: String,
94 },
95
96 /// A `meta()` glob could match an effect-written namespace —
97 /// `refs/meta/results/*` or `refs/meta/index/*` — which must be
98 /// unreachable from `meta()` (`query.meta`, `query.recursion`).
99 #[error(
100 "meta() glob {glob:?} could match the effect-written namespace {namespace} \
101 (query.meta)"
102 )]
103 MetaGlobEffectWritten {
104 /// The glob as written.
105 glob: String,
106 /// The forbidden namespace prefix it could match.
107 namespace: &'static str,
108 },
109
110 /// `rev()` was given an empty expression.
111 #[error("empty rev() expression")]
112 EmptyRev,
113
114 /// `rev()` had only `^`-negated terms; at least one positive term
115 /// is required to denote a non-trivial set.
116 #[error("rev() needs at least one positive (non-negated) term")]
117 NoPositiveRev,
118
119 /// A revspec form this evaluator does not support yet. Unsupported
120 /// forms are an explicit error, never a silent empty set.
121 #[error(
122 "unsupported revspec form {token:?}: supported forms are refnames, refs/ globs, \
123 full hex object ids, ^negation, and A..B ranges"
124 )]
125 UnsupportedRev {
126 /// The unsupported token.
127 token: String,
128 },
129
130 /// A ref pattern contained bytes a refname can never contain.
131 #[error("invalid ref pattern {pattern:?}: {why}")]
132 BadPattern {
133 /// The pattern as written.
134 pattern: String,
135 /// What is wrong with it.
136 why: &'static str,
137 },
138}
139
140/// Everything that can prevent evaluation from completing — always
141/// infrastructure, never a property of the query.
142#[derive(Debug, thiserror::Error)]
143#[non_exhaustive]
144pub enum EvalError {
145 /// The ref store's read half failed.
146 #[error("ref store read failed: {0}")]
147 Refs(#[from] gix_ref_store::Error),
148
149 /// The object store failed while looking up `oid`.
150 #[error("object lookup failed for {oid}: {source}")]
151 Object {
152 /// The object being looked up.
153 oid: ObjectId,
154 /// The underlying object-store error.
155 #[source]
156 source: gix_object::find::Error,
157 },
158
159 /// `oid` was referenced (by a ref tip or a parent edge) but is not
160 /// in the object store.
161 #[error("object {oid} is missing from the object store")]
162 Missing {
163 /// The absent object.
164 oid: ObjectId,
165 },
166
167 /// `oid` exists but could not be decoded as a commit.
168 #[error("object {oid} could not be decoded: {detail}")]
169 Decode {
170 /// The undecodable object.
171 oid: ObjectId,
172 /// What failed, human-readable.
173 detail: String,
174 },
175
176 /// A results ref's tip tree did not deserialize as a recorded
177 /// [`ents_model::Status`]. Evaluation fails rather than guessing a
178 /// status (`model.result-taxonomy` is a closed taxonomy).
179 #[error("results ref {name} has an unreadable status tree: {source}")]
180 Status {
181 /// The results refname.
182 name: String,
183 /// The typed-tree deserialization error.
184 #[source]
185 source: facet_git_tree::Error,
186 },
187}
188
189/// The `Result` alias for evaluation operations.
190pub type EvalResult<T> = std::result::Result<T, EvalError>;