1use serde::{Deserialize, Deserializer, Serialize, Serializer};
2use std::fmt;
3use std::ops::{Add, Sub};
4use std::time::Duration;
5
6#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default)]
7pub struct MemorySize(usize);
8
9impl MemorySize {
10 pub fn new(bytes: usize) -> Self {
11 MemorySize(bytes)
12 }
13
14 pub fn as_bytes(&self) -> usize {
15 self.0
16 }
17
18 pub fn as_kilobytes(&self) -> usize {
19 self.0 / 1024
20 }
21
22 pub fn as_megabytes(&self) -> usize {
23 self.as_kilobytes() / 1024
24 }
25
26 pub fn as_gigabytes(&self) -> usize {
27 self.as_megabytes() / 1024
28 }
29}
30
31impl fmt::Display for MemorySize {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 if self.0 % 1024 == 0 {
34 if self.0 % (1024 * 1024) == 0 {
35 if self.0 % (1024 * 1024 * 1024) == 0 {
36 write!(f, "{}GB", self.as_gigabytes())
37 } else {
38 write!(f, "{}MB", self.as_megabytes())
39 }
40 } else {
41 write!(f, "{}KB", self.as_kilobytes())
42 }
43 } else {
44 write!(f, "{}B", self.0)
45 }
46 }
47}
48
49impl MemorySize {
50 pub fn from_bytes(value: usize) -> Self {
51 Self::new(value)
52 }
53
54 pub fn from_kilobytes(value: usize) -> Self {
55 MemorySize::new(value * 1024)
56 }
57
58 pub fn from_megabytes(value: usize) -> Self {
59 MemorySize::new(value * 1024 * 1024)
60 }
61
62 pub fn from_gigabytes(value: usize) -> Self {
63 MemorySize::new(value * 1024 * 1024 * 1024)
64 }
65}
66
67impl Add for MemorySize {
68 type Output = Self;
69
70 fn add(self, other: Self) -> Self::Output {
71 MemorySize::new(self.0 + other.0)
72 }
73}
74
75impl Sub for MemorySize {
76 type Output = Self;
77
78 fn sub(self, other: Self) -> Self::Output {
79 if self.0 >= other.0 {
80 MemorySize::new(self.0 - other.0)
81 } else {
82 MemorySize::new(0)
83 }
84 }
85}
86
87impl Serialize for MemorySize {
88 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
89 where
90 S: Serializer,
91 {
92 if self.0 % 1024 == 0 {
93 if self.0 % (1024 * 1024) == 0 {
94 if self.0 % (1024 * 1024 * 1024) == 0 {
95 serializer.serialize_str(format!("{}GB", self.as_gigabytes()).as_str())
96 } else {
97 serializer.serialize_str(format!("{}MB", self.as_megabytes()).as_str())
98 }
99 } else {
100 serializer.serialize_str(format!("{}KB", self.as_kilobytes()).as_str())
101 }
102 } else {
103 serializer.serialize_str(format!("{}B", self.0).as_str())
104 }
105 }
106}
107
108impl<'de> Deserialize<'de> for MemorySize {
109 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
110 where
111 D: Deserializer<'de>,
112 {
113 struct MemorySizeVisitor;
114
115 impl<'de> serde::de::Visitor<'de> for MemorySizeVisitor {
116 type Value = MemorySize;
117
118 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
119 formatter.write_str("a string representing MemorySize (e.g., '1024B')")
120 }
121
122 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
123 where
124 E: serde::de::Error,
125 {
126 let (number, unit) =
128 value.split_at(value.trim_end_matches(|c| char::is_alphabetic(c)).len());
129 let bytes = match unit.trim() {
130 "B" => 1,
131 "KB" => 1024,
132 "MB" => 1024 * 1024,
133 "GB" => 1024 * 1024 * 1024,
134 _ => return Err(serde::de::Error::custom("Invalid MemorySize unit")),
135 };
136
137 if let Ok(value) = number.parse::<usize>() {
138 Ok(MemorySize::new(value * bytes))
139 } else {
140 Err(serde::de::Error::custom("Invalid MemorySize format"))
141 }
142 }
143 }
144 deserializer.deserialize_str(MemorySizeVisitor)
145 }
146}
147
148#[derive(Debug, Eq, PartialOrd, Ord, Clone, Copy, Default, PartialEq)]
149pub struct TimeSpan(u64);
150
151impl TimeSpan {
152 pub fn from_milliseconds(milliseconds: u64) -> Self {
153 TimeSpan(milliseconds)
154 }
155
156 pub fn from_seconds(seconds: u64) -> Self {
157 TimeSpan(seconds * 1_000)
158 }
159
160 pub fn from_minutes(minutes: u64) -> Self {
161 TimeSpan(minutes * 60 * 1_000)
162 }
163
164 pub fn from_hours(hours: u64) -> Self {
165 TimeSpan(hours * 60 * 60 * 1_000)
166 }
167
168 pub fn as_milliseconds(&self) -> u64 {
169 self.0
170 }
171
172 pub fn as_seconds(&self) -> u64 {
173 self.0 / 1_000
174 }
175
176 pub fn as_minutes(&self) -> u64 {
177 self.0 / 60 / 1_000
178 }
179
180 pub fn as_hours(&self) -> u64 {
181 self.0 / 60 / 60 / 1_000
182 }
183}
184
185impl From<Duration> for TimeSpan {
186 fn from(duration: Duration) -> Self {
187 TimeSpan(duration.as_millis() as u64)
188 }
189}
190
191impl From<TimeSpan> for Duration {
192 fn from(timespan: TimeSpan) -> Self {
193 Duration::from_millis(timespan.0)
194 }
195}
196
197impl fmt::Display for TimeSpan {
198 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
199 write!(f, "{}ms", self.as_milliseconds())
200 }
201}
202
203impl Serialize for TimeSpan {
204 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
205 where
206 S: Serializer,
207 {
208 if self.0 % 1000 == 0 {
209 if self.0 % (1000 * 60) == 0 {
210 if self.0 % (1000 * 60 * 60) == 0 {
211 serializer.serialize_str(format!("{}h", self.as_hours()).as_str())
212 } else {
213 serializer.serialize_str(format!("{}m", self.as_minutes()).as_str())
214 }
215 } else {
216 serializer.serialize_str(format!("{}s", self.as_seconds()).as_str())
217 }
218 } else {
219 serializer.serialize_str(format!("{}ms", self.0).as_str())
220 }
221 }
222}
223
224impl<'de> Deserialize<'de> for TimeSpan {
225 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
226 where
227 D: Deserializer<'de>,
228 {
229 struct TimeSpanVisitor;
230
231 impl<'de> serde::de::Visitor<'de> for TimeSpanVisitor {
232 type Value = TimeSpan; fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
235 formatter.write_str(
236 "a string representing TimeSpan (e.g., '60s', '120m', '24h', '500ms')",
237 )
238 }
239
240 fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
241 where
242 E: serde::de::Error,
243 {
244 let (number, unit) =
246 value.split_at(value.trim_end_matches(|c| char::is_alphabetic(c)).len());
247 let ms = match unit.trim() {
248 "ms" => 1,
249 "s" => 1000,
250 "m" => 60 * 1000,
251 "h" => 60 * 60 * 1000,
252 _ => return Err(serde::de::Error::custom("Invalid TimeSpan unit")),
253 };
254
255 if let Ok(value) = number.parse::<u64>() {
256 Ok(TimeSpan::from_milliseconds(value * ms)) } else {
258 Err(serde::de::Error::custom("Invalid TimeSpan format"))
259 }
260 }
261 }
262 deserializer.deserialize_str(TimeSpanVisitor)
263 }
264}
265
266impl Add for TimeSpan {
267 type Output = Self;
268
269 fn add(self, other: Self) -> Self::Output {
270 TimeSpan(self.0 + other.0)
271 }
272}
273
274impl Sub for TimeSpan {
275 type Output = Self;
276
277 fn sub(self, other: Self) -> Self::Output {
278 TimeSpan(self.0 - other.0)
279 }
280}
281
282#[derive(Debug, Clone, Default, Deserialize, Serialize)]
283pub struct ProcessResource {
284 pub runtime: TimeSpan,
285 pub memory: MemorySize,
286 pub stdout: Vec<u8>,
287 pub stderr: Vec<u8>,
288}
289
290impl ProcessResource {
291 pub fn default() -> Self {
292 ProcessResource {
293 runtime: TimeSpan::default(),
294 memory: MemorySize::default(),
295 stdout: vec![],
296 stderr: vec![],
297 }
298 }
299}
300
301impl fmt::Display for ProcessResource {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 let stdout_str = String::from_utf8_lossy(&self.stdout);
304 let stderr_str = String::from_utf8_lossy(&self.stderr);
305
306 let stdout_chars: String = stdout_str.chars().take(256).collect();
307 let stderr_chars: String = stderr_str.chars().take(256).collect();
308
309 let stdout_escaped: String = stdout_chars
310 .bytes()
311 .flat_map(std::ascii::escape_default)
312 .map(|b| b as char)
313 .collect();
314 let stderr_escaped: String = stderr_chars
315 .bytes()
316 .flat_map(std::ascii::escape_default)
317 .map(|b| b as char)
318 .collect();
319 let stdout_escaped = if stdout_str.len() > 256 {
320 format!("{}... ({} chars total)", stdout_escaped, stdout_str.len())
321 } else {
322 stdout_escaped
323 };
324 let stderr_escaped = if stderr_str.len() > 256 {
325 format!("{}... ({} chars total)", stderr_escaped, stderr_str.len())
326 } else {
327 stderr_escaped
328 };
329
330 write!(
331 f,
332 "Runtime: {}, Memory: {}, Stdout: {}, Stderr: {}",
333 self.runtime, self.memory, stdout_escaped, stderr_escaped
334 )
335 }
336}