1use crate::{DeriveError, NodeId, OutputKey, ScopeId, TransactionId};
2use core::fmt;
3
4pub type GraphResult<T> = Result<T, GraphError>;
6
7#[derive(Copy, Clone, Debug, Eq, PartialEq)]
9pub enum ErrorCategory {
10 ProgrammerError,
12 DeriveError,
14 PlanError,
16 OutputError,
18 HostResourceStatus,
20}
21
22#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct ErrorAuditEvent {
25 pub category: ErrorCategory,
27 pub target: ErrorTarget,
29}
30
31#[derive(Copy, Clone, Debug, Eq, PartialEq)]
33pub enum ErrorTarget {
34 Graph,
36 Node(NodeId),
38 Scope(ScopeId),
40 Transaction(TransactionId),
42 Output(OutputKey),
44}
45
46#[derive(Clone, Debug, Eq, PartialEq)]
48pub enum PlanError {
49 Message(String),
51}
52
53impl PlanError {
54 pub fn message(message: impl Into<String>) -> Self {
56 Self::Message(message.into())
57 }
58}
59
60#[derive(Clone, Debug, Eq, PartialEq)]
62pub enum OutputError {
63 Read(DeriveError),
65 Message(String),
67}
68
69impl OutputError {
70 pub fn message(message: impl Into<String>) -> Self {
72 Self::Message(message.into())
73 }
74}
75
76impl From<DeriveError> for OutputError {
77 fn from(error: DeriveError) -> Self {
78 Self::Read(error)
79 }
80}
81
82#[derive(Clone, Debug, Eq, PartialEq)]
84pub enum HostResourceStatus {
85 Unknown,
87 Open,
89 Failed(String),
91 Closed,
93}
94
95impl HostResourceStatus {
96 pub const fn category(&self) -> ErrorCategory {
98 ErrorCategory::HostResourceStatus
99 }
100}
101
102#[derive(Clone, Debug, Eq, PartialEq)]
104pub enum GraphError {
105 UnknownNode(NodeId),
107 UnknownScope(ScopeId),
109 DuplicateDependency(NodeId),
111 SelfDependency(NodeId),
113 NodeAlreadyAttached(NodeId),
115 ScopeAlreadyClosed(ScopeId),
117 ScopeClosed(ScopeId),
119 NestedTransaction,
121 TransactionClosed(TransactionId),
123 NotInputNode(NodeId),
125 NotDerivedNode(NodeId),
127 NotCollectionNode(NodeId),
129 WrongInputType(NodeId),
131 WrongDerivedType(NodeId),
133 WrongCollectionType(NodeId),
135 UnknownOutput(OutputKey),
137 OutputFailed(OutputKey, OutputError),
139 PlanFailed(ScopeId, PlanError),
141 ResourceScopeMismatch(ScopeId),
143 ResourceNotOwned,
145 CycleDetected(NodeId),
147 CollectionDependencyNotAllowed(NodeId),
149 DeriveFailed(NodeId, DeriveError),
151 CollectionFailed(NodeId, DeriveError),
153 FullRecomputeMismatch(NodeId),
155}
156
157impl fmt::Display for GraphError {
158 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159 match self {
160 Self::UnknownNode(id) => write!(f, "unknown node: {id:?}"),
161 Self::UnknownScope(id) => write!(f, "unknown scope: {id:?}"),
162 Self::DuplicateDependency(id) => write!(f, "duplicate dependency: {id:?}"),
163 Self::SelfDependency(id) => write!(f, "self dependency: {id:?}"),
164 Self::NodeAlreadyAttached(id) => write!(f, "node already attached: {id:?}"),
165 Self::ScopeAlreadyClosed(id) => write!(f, "scope already closed: {id:?}"),
166 Self::ScopeClosed(id) => write!(f, "scope already closed: {id:?}"),
167 Self::NestedTransaction => write!(f, "a transaction is already open"),
168 Self::TransactionClosed(id) => write!(f, "transaction already closed: {id:?}"),
169 Self::NotInputNode(id) => write!(f, "node is not an input: {id:?}"),
170 Self::NotDerivedNode(id) => write!(f, "node is not derived: {id:?}"),
171 Self::NotCollectionNode(id) => write!(f, "node is not a collection: {id:?}"),
172 Self::WrongInputType(id) => write!(f, "wrong input value type for node: {id:?}"),
173 Self::WrongDerivedType(id) => write!(f, "wrong derived value type for node: {id:?}"),
174 Self::WrongCollectionType(id) => {
175 write!(f, "wrong collection value type for node: {id:?}")
176 }
177 Self::UnknownOutput(key) => write!(f, "unknown output: {key:?}"),
178 Self::OutputFailed(key, error) => write!(f, "output failed for {key:?}: {error:?}"),
179 Self::PlanFailed(scope, error) => {
180 write!(f, "resource planner failed for {scope:?}: {error:?}")
181 }
182 Self::ResourceScopeMismatch(id) => write!(f, "resource scope mismatch: {id:?}"),
183 Self::ResourceNotOwned => write!(f, "resource is not owned"),
184 Self::CycleDetected(id) => write!(f, "dependency cycle detected at node: {id:?}"),
185 Self::CollectionDependencyNotAllowed(id) => {
186 write!(
187 f,
188 "collection dependency is not allowed for derived node: {id:?}"
189 )
190 }
191 Self::DeriveFailed(id, error) => write!(f, "derive failed for {id:?}: {error:?}"),
192 Self::CollectionFailed(id, error) => {
193 write!(f, "collection failed for {id:?}: {error:?}")
194 }
195 Self::FullRecomputeMismatch(id) => {
196 write!(f, "full recompute mismatch for node: {id:?}")
197 }
198 }
199 }
200}
201
202impl GraphError {
203 pub const fn category(&self) -> ErrorCategory {
205 match self {
206 Self::DeriveFailed(_, _) | Self::CollectionFailed(_, _) => ErrorCategory::DeriveError,
207 Self::PlanFailed(_, _) => ErrorCategory::PlanError,
208 Self::OutputFailed(_, _) => ErrorCategory::OutputError,
209 _ => ErrorCategory::ProgrammerError,
210 }
211 }
212
213 pub const fn audit_event(&self) -> ErrorAuditEvent {
215 ErrorAuditEvent {
216 category: self.category(),
217 target: match self {
218 Self::UnknownNode(node)
219 | Self::DuplicateDependency(node)
220 | Self::SelfDependency(node)
221 | Self::NodeAlreadyAttached(node)
222 | Self::NotInputNode(node)
223 | Self::NotDerivedNode(node)
224 | Self::NotCollectionNode(node)
225 | Self::WrongInputType(node)
226 | Self::WrongDerivedType(node)
227 | Self::WrongCollectionType(node)
228 | Self::CycleDetected(node)
229 | Self::CollectionDependencyNotAllowed(node)
230 | Self::DeriveFailed(node, _)
231 | Self::CollectionFailed(node, _)
232 | Self::FullRecomputeMismatch(node) => ErrorTarget::Node(*node),
233 Self::UnknownScope(scope)
234 | Self::ScopeAlreadyClosed(scope)
235 | Self::ScopeClosed(scope)
236 | Self::ResourceScopeMismatch(scope)
237 | Self::PlanFailed(scope, _) => ErrorTarget::Scope(*scope),
238 Self::TransactionClosed(transaction) => ErrorTarget::Transaction(*transaction),
239 Self::UnknownOutput(output) | Self::OutputFailed(output, _) => {
240 ErrorTarget::Output(*output)
241 }
242 Self::NestedTransaction | Self::ResourceNotOwned => ErrorTarget::Graph,
243 },
244 }
245 }
246}
247
248impl std::error::Error for GraphError {}