structfs_ll_store/
error.rs1use bytes::Bytes;
7
8#[derive(Debug)]
13pub enum LLError {
14 Transport(Box<dyn std::error::Error + Send + Sync>),
18
19 NotSupported,
23
24 ResourceExhausted,
28
29 Protocol {
34 code: u32,
36 detail: Bytes,
38 },
39}
40
41impl std::fmt::Display for LLError {
42 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43 match self {
44 LLError::Transport(e) => write!(f, "transport error: {}", e),
45 LLError::NotSupported => write!(f, "operation not supported"),
46 LLError::ResourceExhausted => write!(f, "resource exhausted"),
47 LLError::Protocol { code, detail } => {
48 if detail.is_empty() {
49 write!(f, "protocol error: code {}", code)
50 } else {
51 match std::str::from_utf8(detail) {
53 Ok(s) => write!(f, "protocol error: code {} - {}", code, s),
54 Err(_) => write!(f, "protocol error: code {} - {:?}", code, detail),
55 }
56 }
57 }
58 }
59 }
60}
61
62impl std::error::Error for LLError {
63 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
64 match self {
65 LLError::Transport(e) => Some(e.as_ref()),
66 _ => None,
67 }
68 }
69}
70
71impl From<std::io::Error> for LLError {
72 fn from(e: std::io::Error) -> Self {
73 LLError::Transport(Box::new(e))
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use std::error::Error as StdError;
81
82 #[test]
83 fn error_display_works() {
84 let e = LLError::NotSupported;
85 assert_eq!(format!("{}", e), "operation not supported");
86
87 let e = LLError::Protocol {
88 code: 42,
89 detail: Bytes::from_static(b"something went wrong"),
90 };
91 assert!(format!("{}", e).contains("42"));
92 assert!(format!("{}", e).contains("something went wrong"));
93 }
94
95 #[test]
96 fn resource_exhausted_display() {
97 let e = LLError::ResourceExhausted;
98 assert_eq!(format!("{}", e), "resource exhausted");
99 }
100
101 #[test]
102 fn protocol_empty_detail_display() {
103 let e = LLError::Protocol {
104 code: 100,
105 detail: Bytes::new(),
106 };
107 assert_eq!(format!("{}", e), "protocol error: code 100");
108 }
109
110 #[test]
111 fn protocol_non_utf8_detail_display() {
112 let e = LLError::Protocol {
113 code: 200,
114 detail: Bytes::from_static(&[0xFF, 0xFE, 0x00]),
115 };
116 let display = format!("{}", e);
117 assert!(display.contains("200"));
118 assert!(display.contains("protocol error"));
120 }
121
122 #[test]
123 fn transport_error_display() {
124 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
125 let e = LLError::Transport(Box::new(io_err));
126 let display = format!("{}", e);
127 assert!(display.contains("transport error"));
128 assert!(display.contains("file not found"));
129 }
130
131 #[test]
132 fn transport_error_source() {
133 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
134 let e = LLError::Transport(Box::new(io_err));
135 assert!(StdError::source(&e).is_some());
136 }
137
138 #[test]
139 fn non_transport_error_source_is_none() {
140 let e = LLError::NotSupported;
141 assert!(StdError::source(&e).is_none());
142
143 let e = LLError::ResourceExhausted;
144 assert!(StdError::source(&e).is_none());
145
146 let e = LLError::Protocol {
147 code: 1,
148 detail: Bytes::new(),
149 };
150 assert!(StdError::source(&e).is_none());
151 }
152
153 #[test]
154 fn io_error_converts() {
155 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
156 let ll_err: LLError = io_err.into();
157 assert!(matches!(ll_err, LLError::Transport(_)));
158 }
159}