1use std::{collections::BTreeMap, fmt::Debug};
2
3use derive_more::{Display, Error, IsVariant};
4
5#[derive(Clone, Error)]
8#[non_exhaustive]
9pub struct StartError {
10 pub errors: Vec<StartGroupError>,
11}
12
13impl StartError {
14 pub(crate) fn single(group: String, reason: String) -> Self {
15 Self {
16 errors: vec![StartGroupError { group, reason }],
17 }
18 }
19
20 pub(crate) fn multiple(errors: Vec<StartGroupError>) -> Self {
21 Self { errors }
22 }
23}
24
25fn group_errors(errors: Vec<StartGroupError>) -> BTreeMap<String, Vec<String>> {
26 let mut group_errors = BTreeMap::<String, Vec<String>>::new();
29 for error in errors {
30 group_errors
31 .entry(error.group)
32 .or_default()
33 .push(error.reason);
34 }
35 for errors in group_errors.values_mut() {
37 errors.sort();
38 }
39 group_errors
40}
41
42impl Debug for StartError {
43 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
44 if f.alternate() {
45 let mut s = f.debug_struct("StartError");
46 s.field("errors", &self.errors);
47 s.finish()
48 } else {
49 write!(f, "failed to start\n\n")?;
50 for (group, errors) in group_errors(self.errors.clone()) {
51 writeln!(f, "{group}:")?;
52 for error in errors {
53 writeln!(f, "- {error}")?;
54 }
55 writeln!(f)?;
56 }
57 Ok(())
58 }
59 }
60}
61
62impl std::fmt::Display for StartError {
63 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
64 write!(f, "failed to start: ")?;
65 let mut i = 1;
66 for (group, errors) in group_errors(self.errors.clone()) {
67 for error in errors {
68 write!(f, "{i}. {error} ({group}); ")?;
69 i += 1;
70 }
71 }
72 Ok(())
73 }
74}
75
76#[derive(Clone, Debug, Display, Error)]
77#[non_exhaustive]
78#[display("error from group {group}: {reason}")]
79pub struct StartGroupError {
80 pub group: String,
81 pub reason: String,
82}
83
84#[derive(Clone, Debug, Display, Error)]
87#[display("mailbox closed")]
88pub struct SendError<T>(#[error(not(source))] pub T);
89
90impl<T> SendError<T> {
91 #[inline]
92 pub fn into_inner(self) -> T {
93 self.0
94 }
95
96 #[inline]
98 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> SendError<U> {
99 SendError(f(self.0))
100 }
101}
102
103#[derive(Clone, Debug, Display, Error)]
106pub enum TrySendError<T> {
107 #[display("mailbox full")]
109 Full(#[error(not(source))] T),
110 #[display("mailbox closed")]
112 Closed(#[error(not(source))] T),
113}
114
115impl<T> TrySendError<T> {
116 #[inline]
118 pub fn into_inner(self) -> T {
119 match self {
120 Self::Closed(inner) => inner,
121 Self::Full(inner) => inner,
122 }
123 }
124
125 #[inline]
127 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> TrySendError<U> {
128 match self {
129 Self::Full(inner) => TrySendError::Full(f(inner)),
130 Self::Closed(inner) => TrySendError::Closed(f(inner)),
131 }
132 }
133
134 #[inline]
136 pub fn is_full(&self) -> bool {
137 matches!(self, Self::Full(_))
138 }
139
140 #[inline]
142 pub fn is_closed(&self) -> bool {
143 matches!(self, Self::Closed(_))
144 }
145}
146
147impl<T> From<SendError<T>> for TrySendError<T> {
148 #[inline]
149 fn from(err: SendError<T>) -> Self {
150 TrySendError::Closed(err.0)
151 }
152}
153
154#[derive(Debug, Clone, IsVariant, Display, Error)]
157pub enum RequestError {
158 #[display("request failed")]
160 Failed,
161 #[display("request ignored")]
163 Ignored,
164}
165
166#[derive(Debug, Clone, Display, Error)]
169pub enum TryRecvError {
170 #[display("mailbox empty")]
172 Empty,
173 #[display("mailbox closed")]
175 Closed,
176}
177
178impl TryRecvError {
179 #[inline]
181 pub fn is_empty(&self) -> bool {
182 matches!(self, Self::Empty)
183 }
184
185 #[inline]
187 pub fn is_closed(&self) -> bool {
188 matches!(self, Self::Closed)
189 }
190}