1use std::{any::type_name, collections::HashMap, hash::Hash, time::Duration};
90
91pub mod bool_utils;
92pub mod logger;
93pub mod option_utils;
94pub mod str_utils;
95
96pub mod prelude {
97 pub use crate::bool_utils::*;
98 pub use crate::logger::Loggable;
99 pub use crate::option_utils::*;
100 pub use crate::str_utils::*;
101 pub use crate::*;
102}
103
104pub trait EqUtils<T: PartialEq> {
106 fn eq_to(&self, other: &T) -> bool;
108
109 fn not_eq_to(&self, other: &T) -> bool;
111}
112
113impl<T: PartialEq> EqUtils<T> for T {
114 fn eq_to(&self, other: &T) -> bool {
115 self == other
116 }
117 fn not_eq_to(&self, other: &T) -> bool {
118 self != other
119 }
120}
121
122pub trait MemUtils {
124 fn type_name(&self) -> &'static str;
126
127 fn mem_size(&self) -> usize;
129
130 fn view(&self);
132}
133
134impl<T> MemUtils for T {
135 fn type_name(&self) -> &'static str {
136 type_name::<T>()
137 }
138 fn mem_size(&self) -> usize {
139 std::mem::size_of::<T>()
140 }
141 fn view(&self) {
142 println!(
143 "[view] Type: {}, Size: {} bytes",
144 self.type_name(),
145 self.mem_size()
146 );
147 }
148}
149
150pub trait ConvertUtils: Sized {
151 fn to<T: TryFrom<Self>>(self) -> Option<T>;
152 fn to_or<T: TryFrom<Self>>(self, fallback: T) -> T;
153 fn to_result<T: TryFrom<Self>>(self) -> Result<T, T::Error>;
154}
155
156impl<T> ConvertUtils for T {
157 fn to<U: TryFrom<T>>(self) -> Option<U> {
158 U::try_from(self).ok()
159 }
160
161 fn to_or<U: TryFrom<T>>(self, fallback: U) -> U {
162 self.to().unwrap_or(fallback)
163 }
164
165 fn to_result<U: TryFrom<T>>(self) -> Result<U, U::Error> {
166 U::try_from(self)
167 }
168}
169
170pub trait VecUtils<T> {
172 fn push_if(&mut self, push: T, cond: bool);
174
175 fn push_if_with<F: FnOnce() -> T>(&mut self, cond: bool, f: F);
177}
178
179impl<T> VecUtils<T> for Vec<T> {
180 fn push_if(&mut self, push: T, cond: bool) {
181 if cond {
182 self.push(push);
183 }
184 }
185 fn push_if_with<F: FnOnce() -> T>(&mut self, cond: bool, f: F) {
186 if cond {
187 self.push(f());
188 }
189 }
190}
191
192pub trait MapUtils<K, V> {
193 fn get_or<'a>(&'a self, key: &K, fallback: &'a V) -> &'a V;
194 fn insert_if(&mut self, key: K, value: V, cond: bool);
195}
196
197impl<K: Eq + Hash, V> MapUtils<K, V> for HashMap<K, V> {
198 fn get_or<'a>(&'a self, key: &K, fallback: &'a V) -> &'a V {
199 self.get(key).unwrap_or(fallback)
200 }
201
202 fn insert_if(&mut self, key: K, value: V, cond: bool) {
203 if cond {
204 self.insert(key, value);
205 }
206 }
207}
208
209pub trait ResultUtils<T, E> {
210 fn if_ok<F: FnOnce(&T)>(self, f: F) -> Self;
211 fn if_err<F: FnOnce(&E)>(self, f: F) -> Self;
212}
213
214impl<T, E: std::fmt::Debug> ResultUtils<T, E> for Result<T, E> {
215 fn if_ok<F: FnOnce(&T)>(self, f: F) -> Self {
216 if let Ok(ref val) = self {
217 f(val);
218 }
219 self
220 }
221
222 fn if_err<F: FnOnce(&E)>(self, f: F) -> Self {
223 if let Err(ref err) = self {
224 f(err);
225 }
226 self
227 }
228}
229
230pub trait DurationUtils {
232 fn pretty(&self) -> String;
234}
235
236impl DurationUtils for Duration {
237 fn pretty(&self) -> String {
238 let total_secs = self.as_secs();
239 let hours = total_secs / 3600;
240 let mins = (total_secs % 3600) / 60;
241 let secs = total_secs % 60;
242 format!("{}h {}m {}s", hours, mins, secs)
243 }
244}
245
246pub trait IteratorUtils: Iterator + Sized {
247 fn find_map_or<T, F: FnMut(Self::Item) -> Option<T>>(self, f: F, fallback: T) -> T;
248}
249
250impl<I: Iterator> IteratorUtils for I {
251 fn find_map_or<T, F: FnMut(Self::Item) -> Option<T>>(mut self, f: F, fallback: T) -> T {
252 self.find_map(f).unwrap_or(fallback)
253 }
254}
255
256pub trait IdentityUtils: Sized {
257 fn tap<F: FnOnce(&Self)>(self, f: F) -> Self;
258}
259
260impl<T> IdentityUtils for T {
261 fn tap<F: FnOnce(&Self)>(self, f: F) -> Self {
262 f(&self);
263 self
264 }
265}
266
267pub trait PanicUtils<T> {
269 fn unwrap_or_exit(self, msg: &str) -> T;
271}
272
273impl<T> PanicUtils<T> for Option<T> {
274 fn unwrap_or_exit(self, msg: &str) -> T {
275 self.unwrap_or_else(|| {
276 eprintln!("[FATAL]: {}", msg);
277 std::process::exit(1);
278 })
279 }
280}
281
282impl<T, U> PanicUtils<T> for Result<T, U> {
283 fn unwrap_or_exit(self, msg: &str) -> T {
284 self.unwrap_or_else(|_| {
285 eprintln!("[FATAL]: {}", msg);
286 std::process::exit(1);
287 })
288 }
289}
290
291pub trait ClampUtils {
292 fn clamp_to(self, min: Self, max: Self) -> Self;
293}
294impl ClampUtils for i32 {
295 fn clamp_to(self, min: Self, max: Self) -> Self {
296 self.max(min).min(max)
297 }
298}
299
300pub trait NumberUtils {
301 #[must_use]
302 fn is_even(&self) -> bool;
303 #[must_use]
304 fn is_odd(&self) -> bool;
305}
306
307impl NumberUtils for i32 {
308 fn is_even(&self) -> bool {
309 self % 2 == 0
310 }
311 fn is_odd(&self) -> bool {
312 self % 2 != 0
313 }
314}