1use thiserror::Error;
4use uuid::Uuid;
5
6pub type FoldResult<T> = std::result::Result<T, FoldError>;
8
9#[derive(Error, Debug)]
11pub enum FoldError {
12 #[error("Entry {0} not found")]
14 EntryNotFound(Uuid),
15
16 #[error("Invalid entry type: expected {expected}, got {actual}")]
18 InvalidEntryType {
19 expected: String,
21 actual: String,
23 },
24
25 #[error("Context error: {0}")]
27 Context(String),
28
29 #[error("Serialization error: {0}")]
31 Serialization(#[from] serde_json::Error),
32
33 #[error("Storage error: {0}")]
35 Storage(String),
36
37 #[error("Internal lock poisoned: {0}")]
39 LockPoisoned(String),
40
41 #[error("invalid input: {0}")]
43 InvalidInput(String),
44
45 #[error("budget exhausted: needed {needed}, have {budget}")]
47 BudgetExhausted {
48 needed: usize,
50 budget: usize,
52 },
53
54 #[error("anchor not found: {0}")]
56 AnchorNotFound(String),
57
58 #[error("required component not configured: {0}")]
60 ComponentMissing(String),
61
62 #[error("checkpoint integrity mismatch for '{id}': stored {stored}, computed {computed}")]
64 IntegrityMismatch {
65 id: String,
67 stored: String,
69 computed: String,
71 },
72
73 #[error("checkpoint not found: {0}")]
75 CheckpointNotFound(String),
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 #[test]
83 fn test_entry_not_found_display() {
84 let id = Uuid::new_v4();
85 let err = FoldError::EntryNotFound(id);
86 assert!(err.to_string().contains(&id.to_string()));
87 }
88
89 #[test]
90 fn test_invalid_entry_type_display() {
91 let err = FoldError::InvalidEntryType {
92 expected: "data".into(),
93 actual: "item".into(),
94 };
95 let msg = err.to_string();
96 assert!(msg.contains("data"));
97 assert!(msg.contains("item"));
98 }
99
100 #[test]
101 fn test_context_display() {
102 let err = FoldError::Context("missing budget".into());
103 assert!(err.to_string().contains("missing budget"));
104 }
105
106 #[test]
107 fn test_from_serde_error() {
108 let json_err: serde_json::Error = serde_json::from_str::<i32>("invalid").unwrap_err();
109 let err: FoldError = json_err.into();
110 assert!(matches!(err, FoldError::Serialization(_)));
111 }
112
113 #[test]
114 fn test_budget_exhausted_display() {
115 let err = FoldError::BudgetExhausted {
116 needed: 100,
117 budget: 50,
118 };
119 let msg = err.to_string();
120 assert!(msg.contains("100"));
121 assert!(msg.contains("50"));
122 }
123
124 #[test]
125 fn test_anchor_not_found_display() {
126 let err = FoldError::AnchorNotFound("my-anchor".into());
127 assert!(err.to_string().contains("my-anchor"));
128 }
129}