panproto_vcs/error.rs
1//! Error types for the VCS engine.
2
3use std::fmt;
4
5/// All errors produced by the VCS engine.
6#[derive(Debug, thiserror::Error)]
7#[non_exhaustive]
8pub enum VcsError {
9 /// An object was not found in the store.
10 #[error("object not found: {id}")]
11 ObjectNotFound {
12 /// The missing object's ID.
13 id: crate::ObjectId,
14 },
15
16 /// A ref was not found.
17 #[error("ref not found: {name}")]
18 RefNotFound {
19 /// The missing ref name.
20 name: String,
21 },
22
23 /// HEAD is detached when a branch was expected.
24 #[error("HEAD is detached")]
25 DetachedHead,
26
27 /// Nothing is staged for commit.
28 #[error("nothing staged")]
29 NothingStaged,
30
31 /// Staging validation failed.
32 #[error("validation failed: {reasons:?}")]
33 ValidationFailed {
34 /// The validation errors.
35 reasons: Vec<String>,
36 },
37
38 /// Merge produced conflicts.
39 #[error("merge conflict: {count} conflict(s)")]
40 MergeConflicts {
41 /// The number of conflicts.
42 count: usize,
43 },
44
45 /// A branch already exists.
46 #[error("branch already exists: {name}")]
47 BranchExists {
48 /// The branch name.
49 name: String,
50 },
51
52 /// Not inside a panproto repository.
53 #[error("not a panproto repository")]
54 NotARepository,
55
56 /// An expected object had the wrong type.
57 #[error("expected {expected} object, found {found}")]
58 WrongObjectType {
59 /// The expected object type.
60 expected: &'static str,
61 /// The actual object type.
62 found: &'static str,
63 },
64
65 /// I/O error.
66 #[error("io error: {0}")]
67 Io(#[from] std::io::Error),
68
69 /// Serialization / deserialization error.
70 #[error("serialization error: {0}")]
71 Serialization(SerializationError),
72
73 /// Migration composition error.
74 #[error("compose error: {0}")]
75 Compose(#[from] panproto_mig::ComposeError),
76
77 /// No common ancestor found for merge.
78 #[error("no common ancestor found")]
79 NoCommonAncestor,
80
81 /// No path found between two commits.
82 #[error("no path found between commits")]
83 NoPath,
84
85 /// Branch is not fully merged into HEAD.
86 #[error("branch '{name}' is not fully merged")]
87 BranchNotMerged {
88 /// The branch name.
89 name: String,
90 },
91
92 /// A merge or cherry-pick is already in progress.
93 #[error("a {operation} is already in progress")]
94 OperationInProgress {
95 /// The operation type (e.g. "merge", "cherry-pick").
96 operation: String,
97 },
98
99 /// Feature is not yet implemented.
100 #[error("{feature} is not yet implemented")]
101 NotImplemented {
102 /// Description of the unimplemented feature.
103 feature: String,
104 },
105
106 /// Merge cannot fast-forward but --ff-only was requested.
107 #[error("cannot fast-forward; refusing to merge")]
108 FastForwardOnly,
109
110 /// Amend requested but no commits exist.
111 #[error("nothing to amend")]
112 NothingToAmend,
113
114 /// A tag already exists.
115 #[error("tag already exists: {name}")]
116 TagExists {
117 /// The tag name.
118 name: String,
119 },
120
121 /// Data migration failed.
122 #[error("data migration failed: {reason}")]
123 DataMigrationFailed {
124 /// Description of the failure.
125 reason: String,
126 },
127
128 /// An object had the wrong type (owned variant for runtime strings).
129 #[error("type mismatch: expected {expected}, got {got}")]
130 TypeMismatch {
131 /// The expected type name.
132 expected: String,
133 /// The actual type name.
134 got: String,
135 },
136
137 /// I/O error from a string description (for cases where
138 /// `std::io::Error` is not directly available).
139 #[error("io: {0}")]
140 IoError(String),
141
142 /// Two leaves were supplied at the same schema-tree path.
143 ///
144 /// Returned by [`crate::tree::build_tree_from_leaves`] when the
145 /// same path appears twice. Surfacing the duplicate lets callers
146 /// decide how to dedupe rather than silently picking a winner.
147 #[error("duplicate schema-tree path: {path}")]
148 DuplicatePath {
149 /// The offending path, displayed with forward slashes.
150 path: String,
151 },
152
153 /// A leaf was supplied with an empty path.
154 ///
155 /// Returned by [`crate::tree::build_tree_from_leaves`] when a path
156 /// has zero components. Empty paths cannot be placed in the
157 /// directory hierarchy and must not be silently dropped.
158 #[error("empty schema-tree path")]
159 EmptyPath,
160
161 /// A generic error described by a human-readable string.
162 #[error("{0}")]
163 Other(String),
164}
165
166/// Wrapper for serialization errors from rmp-serde.
167#[derive(Debug)]
168pub struct SerializationError(pub String);
169
170impl fmt::Display for SerializationError {
171 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
172 f.write_str(&self.0)
173 }
174}
175
176impl From<rmp_serde::encode::Error> for VcsError {
177 fn from(e: rmp_serde::encode::Error) -> Self {
178 Self::Serialization(SerializationError(e.to_string()))
179 }
180}
181
182impl From<rmp_serde::decode::Error> for VcsError {
183 fn from(e: rmp_serde::decode::Error) -> Self {
184 Self::Serialization(SerializationError(e.to_string()))
185 }
186}