query_flow/
error.rs

1//! Error types for query execution.
2
3use std::fmt;
4use std::sync::Arc;
5
6use crate::key::FullCacheKey;
7
8/// Query errors including both system-level and user errors.
9///
10/// User errors can be propagated using the `?` operator, which automatically
11/// converts any `Into<anyhow::Error>` type into `QueryError::UserError`.
12#[derive(Debug, Clone)]
13pub enum QueryError {
14    /// Query is waiting for async loading to complete.
15    ///
16    /// This is returned when a dependency is still loading via a background task.
17    /// Use `runtime.query_async()` to wait for loading to complete, or handle
18    /// explicitly in your query logic.
19    Suspend,
20
21    /// Dependency cycle detected.
22    ///
23    /// The query graph contains a cycle, which would cause infinite recursion.
24    /// The `path` contains a debug representation of the cycle.
25    Cycle {
26        /// Debug representation of the queries forming the cycle.
27        path: Vec<String>,
28    },
29
30    /// Query execution was cancelled.
31    Cancelled,
32
33    /// A required dependency is missing.
34    MissingDependency {
35        /// Description of the missing dependency.
36        description: String,
37    },
38
39    /// Dependencies were removed during query execution.
40    ///
41    /// This can happen if another thread removes queries or assets
42    /// while this query is being registered.
43    DependenciesRemoved {
44        /// Keys that were not found during registration.
45        missing_keys: Vec<FullCacheKey>,
46    },
47
48    /// User-defined error.
49    ///
50    /// This variant allows user errors to be propagated through the query system
51    /// using the `?` operator. Any type implementing `Into<anyhow::Error>` can be
52    /// converted to this variant.
53    ///
54    /// Unlike system errors (Suspend, Cycle, etc.), UserError results are cached
55    /// and participate in early cutoff optimization.
56    UserError(Arc<anyhow::Error>),
57}
58
59impl fmt::Display for QueryError {
60    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
61        match self {
62            QueryError::Suspend => write!(f, "query suspended: waiting for async loading"),
63            QueryError::Cycle { path } => {
64                write!(f, "dependency cycle detected: {}", path.join(" -> "))
65            }
66            QueryError::Cancelled => write!(f, "query cancelled"),
67            QueryError::MissingDependency { description } => {
68                write!(f, "missing dependency: {}", description)
69            }
70            QueryError::DependenciesRemoved { missing_keys } => {
71                write!(
72                    f,
73                    "dependencies removed during execution: {:?}",
74                    missing_keys
75                )
76            }
77            QueryError::UserError(e) => write!(f, "user error: {}", e),
78        }
79    }
80}
81
82impl<T: Into<anyhow::Error>> From<T> for QueryError {
83    fn from(err: T) -> Self {
84        QueryError::UserError(Arc::new(err.into()))
85    }
86}