1use base_scheduler::Cancelled;
5use std::{any::Any, error, fmt, sync::Arc};
6
7#[derive(Clone, Debug)]
9pub enum BodyError {
10 Cancelled,
11 Closed,
12 Abandoned,
13 InvalidFrame,
14 ChunkTooLarge { length: usize, limit: usize },
15 Failed(Arc<dyn error::Error + Send + Sync>),
16}
17
18impl BodyError {
19 pub fn new<E: error::Error + Send + Sync + 'static>(error: E) -> Self {
21 let mut error = Some(error);
22 if let Some(body) = (&mut error as &mut dyn Any).downcast_mut::<Option<Self>>() {
23 return body.take().unwrap();
24 }
25 Self::Failed(Arc::new(error.unwrap()))
26 }
27}
28
29impl From<Cancelled> for BodyError {
30 fn from(_: Cancelled) -> Self {
31 Self::Cancelled
32 }
33}
34
35impl From<std::io::Error> for BodyError {
36 fn from(error: std::io::Error) -> Self {
37 Self::new(error)
38 }
39}
40
41impl fmt::Display for BodyError {
42 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
43 match self {
44 Self::Cancelled => formatter.write_str("body operation cancelled"),
45 Self::Closed => formatter.write_str("body output is closed"),
46 Self::Abandoned => formatter.write_str("body abandoned before completion"),
47 Self::InvalidFrame => {
48 formatter.write_str("body data or headers after trailing headers")
49 }
50 Self::ChunkTooLarge { length, limit } => write!(
51 formatter,
52 "body frame has {length} bytes, exceeding queue limit {limit}"
53 ),
54 Self::Failed(_) => formatter.write_str("body failed"),
55 }
56 }
57}
58
59impl error::Error for BodyError {
60 fn source(&self) -> Option<&(dyn error::Error + 'static)> {
61 match self {
62 Self::Failed(error) => Some(error.as_ref()),
63 _ => None,
64 }
65 }
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71 use std::{error::Error as _, io};
72
73 #[test]
74 fn failed_reports_the_producer_error_as_its_source() {
75 let error = BodyError::new(io::Error::from(io::ErrorKind::TimedOut));
76 assert_eq!(error.to_string(), "body failed");
77 assert_eq!(error.source().unwrap().to_string(), "timed out");
78 }
79
80 #[test]
81 fn wrapping_a_body_error_returns_it_unchanged() {
82 let error = BodyError::new(BodyError::new(io::Error::other("producer failed")));
83 assert_eq!(error.to_string(), "body failed");
84 assert_eq!(error.source().unwrap().to_string(), "producer failed");
85 assert_eq!(
86 BodyError::new(BodyError::Closed).to_string(),
87 "body output is closed"
88 );
89 }
90}