1use std::{fmt, time::Duration};
2
3use derive_more as dm;
4pub use error_stack::{self, Context, Report, ResultExt};
5
6pub trait Display: fmt::Display + fmt::Debug + Send + Sync + 'static {}
7
8impl<A> Display for A where A: fmt::Display + fmt::Debug + Send + Sync + 'static {}
9
10pub trait Debug: fmt::Debug + Send + Sync + 'static {}
11
12impl<A> Debug for A where A: fmt::Debug + Send + Sync + 'static {}
13
14#[derive(Debug)]
16pub struct Dbg<A: Debug>(pub A);
17
18impl Dbg<String> {
19 pub fn format(attachment: impl fmt::Debug) -> Self {
20 Self(format!("{attachment:?}"))
21 }
22}
23
24impl<A: Debug> fmt::Display for Dbg<A> {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "{:?}", self.0)
27 }
28}
29
30#[derive(Debug, PartialEq, Eq)]
32pub struct KeyValue<K, V>(pub K, pub V);
33
34impl<K: fmt::Display, V: fmt::Display> fmt::Display for KeyValue<K, V> {
35 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36 write!(f, "{}: {}", self.0, self.1)
37 }
38}
39
40impl<K: Display, V: Debug> KeyValue<K, Dbg<V>> {
41 pub const fn dbg(key: K, value: V) -> Self {
42 Self(key, Dbg(value))
43 }
44}
45
46#[macro_export]
49macro_rules! kv {
50 (ty: $value: expr) => {
51 $crate::KeyValue($crate::Type::of_val(&$value), $value)
52 };
53 ($value: expr) => {
54 $crate::KeyValue(stringify!($value), $value)
55 };
56}
57
58#[derive(Debug)]
59pub struct Field<Id, S> {
62 id: Id,
65 status: S,
66}
67
68impl<Id: Display, S: Display> fmt::Display for Field<Id, S> {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(f, "{}: {}", self.id, self.status)
71 }
72}
73
74impl<Id: Display, S: Display> Field<Id, S> {
75 pub const fn new(key: Id, status: S) -> Self {
76 Self { id: key, status }
77 }
78}
79#[derive(PartialEq, Eq)]
82pub struct Type(&'static str);
83
84impl Type {
85 #[must_use]
87 pub fn of<T>() -> Self {
88 Self(simple_type_name::<T>())
89 }
90
91 pub fn of_val<T: ?Sized>(_val: &T) -> Self {
92 Self(simple_type_name::<T>())
93 }
94}
95
96impl fmt::Display for Type {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 write!(f, "<{}>", self.0)
99 }
100}
101
102impl fmt::Debug for Type {
103 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
104 f.debug_tuple("Type").field(&self.0).finish()
105 }
106}
107
108#[macro_export]
109macro_rules! ty {
110 ($type:ty) => {
111 $crate::attachment::Type::of::<$type>()
112 };
113}
114
115#[derive(Debug, dm::Display)]
116#[display("already present")]
117pub struct AlreadyPresent;
118
119#[derive(Debug, dm::Display)]
120#[display("missing")]
121pub struct Missing;
122
123#[derive(Debug, dm::Display)]
124#[display("unsupported")]
125pub struct Unsupported;
126
127#[derive(Debug, dm::Display)]
128#[display("invalid")]
129pub struct Invalid;
130
131#[derive(Debug)]
132pub struct Expectation<E, A> {
133 pub expected: E,
134 pub actual: A,
135}
136
137#[derive(Debug)]
138pub struct FromTo<F, T>(pub F, pub T);
139
140#[allow(dead_code)]
141enum Symbol {
142 Vertical,
143 VerticalRight,
144 Horizontal,
145 HorizontalLeft,
146 HorizontalDown,
147 ArrowRight,
148 CurveRight,
149 Space,
150}
151
152impl fmt::Display for Symbol {
153 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
154 let utf8 = match self {
155 Self::Vertical => "\u{2502}", Self::VerticalRight => "\u{251c}", Self::Horizontal => "\u{2500}", Self::HorizontalLeft => "\u{2574}", Self::HorizontalDown => "\u{252c}", Self::ArrowRight => "\u{25b6}", Self::CurveRight => "\u{2570}", Self::Space => " ",
163 };
164 write!(f, "{utf8}")
165 }
166}
167
168impl<E: Display, A: Display> fmt::Display for Expectation<E, A> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 let curve_right = Symbol::CurveRight;
171 let horizontal_left = Symbol::HorizontalLeft;
172 let expected = KeyValue("expected", &self.expected);
173 let actual = KeyValue("actual", &self.actual);
174 write!(f, "{expected}\n{curve_right}{horizontal_left}{actual}")
177 }
178}
179impl<F: Display, T: Display> fmt::Display for FromTo<F, T> {
180 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
181 let curve_right = Symbol::CurveRight;
182 let horizontal_left = Symbol::HorizontalLeft;
183 let from = KeyValue("from", &self.0);
184 let to = KeyValue("to", &self.1);
185 write!(f, "{from}\n{curve_right}{horizontal_left}{to}")
188 }
189}
190
191#[derive(Debug)]
192pub struct DisplayDuration(pub Duration);
193impl fmt::Display for DisplayDuration {
194 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195 write!(f, "{}", hms_string(self.0))
196 }
197}
198
199impl From<Duration> for DisplayDuration {
200 fn from(duration: Duration) -> Self {
201 Self(duration)
202 }
203}
204
205impl std::ops::Deref for DisplayDuration {
206 type Target = Duration;
207
208 fn deref(&self) -> &Self::Target {
209 &self.0
210 }
211}
212
213#[must_use]
215pub fn hms_string(duration: Duration) -> String {
216 if duration.is_zero() {
217 return "ZERO".to_string();
218 }
219 let s = duration.as_secs();
220 let ms = duration.subsec_millis();
221 if s == 0 {
223 return format!("{ms}ms");
224 }
225 let (h, s) = (s / 3600, s % 3600);
227 let (m, s) = (s / 60, s % 60);
228
229 let mut hms = String::new();
230 if h != 0 {
231 hms += &format!("{h:02}H");
232 }
233 if m != 0 {
234 hms += &format!("{m:02}m");
235 }
236 hms += &format!("{s:02}s");
237
238 hms
239}
240
241#[must_use]
242pub fn simple_type_name<T: ?Sized>() -> &'static str {
243 let full_type = std::any::type_name::<T>();
244 if full_type.contains(['<', '[']) {
246 return full_type;
247 }
248 full_type.rsplit_once("::").map_or(full_type, |t| t.1)
249}
250
251#[derive(Debug, dm::Display)]
256#[display("idx [{0}: {}]", simple_type_name::<I>())]
257pub struct Index<I: fmt::Display>(pub I);
258
259#[cfg(test)]
260mod test {
261 use super::*;
262
263 #[test]
264 fn kv_macro() {
265 let foo = "Foo";
266
267 assert_eq!(kv!(foo), KeyValue("foo", "Foo"));
269 assert_eq!(kv!(ty: foo), KeyValue(Type::of_val(&foo), "Foo"));
271
272 let foo = 13;
273
274 assert_eq!(kv!(ty: foo), KeyValue(Type::of_val(&foo), 13));
276 assert_eq!(kv!(ty: 13), KeyValue(Type::of_val(&13), 13));
278 }
279}