Skip to main content

sim_incremental_core/
error.rs

1//! Error records emitted by the incremental query engine.
2
3use std::{error::Error, fmt};
4
5use crate::BudgetKind;
6
7/// An opaque handle that can resume a budget-stopped root query.
8#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
9pub struct ContinuationToken(u64);
10
11impl ContinuationToken {
12    /// Creates a continuation token from raw bits.
13    #[must_use]
14    pub const fn new(value: u64) -> Self {
15        Self(value)
16    }
17
18    /// Returns the raw token bits.
19    #[must_use]
20    pub const fn get(self) -> u64 {
21        self.0
22    }
23}
24
25/// A typed query verification failure.
26#[derive(Clone, Debug, Eq, PartialEq)]
27pub enum IncrementalError<K> {
28    /// No query was registered for the requested key.
29    UnknownQuery {
30        /// The missing query key.
31        key: K,
32    },
33    /// Query execution attempted to re-enter a key already on the stack.
34    Cycle {
35        /// The cycle path, including the repeated key at the end.
36        path: Vec<K>,
37    },
38    /// A configured budget was exhausted.
39    BudgetExceeded {
40        /// The exhausted budget class.
41        kind: BudgetKind,
42        /// The configured limit.
43        limit: usize,
44        /// The consumed amount at the failure point.
45        consumed: usize,
46        /// A token that resumes the owning root query.
47        continuation: Option<ContinuationToken>,
48    },
49    /// Query code requested cancellation.
50    Cancelled,
51    /// A continuation token was not known to this engine.
52    UnknownContinuation {
53        /// The rejected token.
54        token: ContinuationToken,
55    },
56}
57
58impl<K> IncrementalError<K> {
59    /// Returns the continuation token carried by a budget error, when present.
60    #[must_use]
61    pub fn continuation(&self) -> Option<ContinuationToken> {
62        match self {
63            Self::BudgetExceeded { continuation, .. } => *continuation,
64            _ => None,
65        }
66    }
67}
68
69impl<K: fmt::Debug> fmt::Display for IncrementalError<K> {
70    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
71        match self {
72            Self::UnknownQuery { key } => write!(f, "unknown query {key:?}"),
73            Self::Cycle { path } => write!(f, "incremental query cycle {path:?}"),
74            Self::BudgetExceeded {
75                kind,
76                limit,
77                consumed,
78                ..
79            } => write!(
80                f,
81                "incremental query budget {kind:?} exhausted at {consumed}/{limit}"
82            ),
83            Self::Cancelled => f.write_str("incremental query cancelled"),
84            Self::UnknownContinuation { token } => {
85                write!(f, "unknown continuation token {}", token.get())
86            }
87        }
88    }
89}
90
91impl<K: fmt::Debug> Error for IncrementalError<K> {}
92
93/// A graph snapshot restore failure.
94#[derive(Clone, Debug, Eq, PartialEq)]
95pub enum SnapshotError<K> {
96    /// A snapshot contained the same node key more than once.
97    DuplicateNode {
98        /// The duplicated key.
99        key: K,
100    },
101}
102
103impl<K: fmt::Debug> fmt::Display for SnapshotError<K> {
104    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105        match self {
106            Self::DuplicateNode { key } => write!(f, "duplicate snapshot node {key:?}"),
107        }
108    }
109}
110
111impl<K: fmt::Debug> Error for SnapshotError<K> {}