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
63#[cfg(test)]
64mod tests {
65 use super::*;
66
67 #[test]
68 fn test_entry_not_found_display() {
69 let id = Uuid::new_v4();
70 let err = FoldError::EntryNotFound(id);
71 assert!(err.to_string().contains(&id.to_string()));
72 }
73
74 #[test]
75 fn test_invalid_entry_type_display() {
76 let err = FoldError::InvalidEntryType {
77 expected: "data".into(),
78 actual: "item".into(),
79 };
80 let msg = err.to_string();
81 assert!(msg.contains("data"));
82 assert!(msg.contains("item"));
83 }
84
85 #[test]
86 fn test_context_display() {
87 let err = FoldError::Context("missing budget".into());
88 assert!(err.to_string().contains("missing budget"));
89 }
90
91 #[test]
92 fn test_from_serde_error() {
93 let json_err: serde_json::Error = serde_json::from_str::<i32>("invalid").unwrap_err();
94 let err: FoldError = json_err.into();
95 assert!(matches!(err, FoldError::Serialization(_)));
96 }
97
98 #[test]
99 fn test_budget_exhausted_display() {
100 let err = FoldError::BudgetExhausted {
101 needed: 100,
102 budget: 50,
103 };
104 let msg = err.to_string();
105 assert!(msg.contains("100"));
106 assert!(msg.contains("50"));
107 }
108
109 #[test]
110 fn test_anchor_not_found_display() {
111 let err = FoldError::AnchorNotFound("my-anchor".into());
112 assert!(err.to_string().contains("my-anchor"));
113 }
114}